Список работ

Программная имитация эксперимента по определению ускорения свободного падения

Курсовая работа по дисциплине Программная инженерия

Скрылев Н. А., А-13-13. Руководитель Бартеньев О. В.

Содержание

Постановка задачи

Движение тела только под действием силы тяжести называется свободным падением. Свободно падающее тело движется равноускоренно с постоянным ускорением g, называемым ускорением свободного падения. Величина ускорения g зависит от географической широты местности и от высоты над уровнем моря, например:

В технических расчетах величину ускорения свободного падения обычно принимают равной g =  9.81 м /  с2.

Известны разные методы определения g. В данной работе имитируется баллистический гравиметр, принцип действия которого основан на измерении времени прохождения свободно падающего тела через несколько точек, расстояния между которыми известны (рис. 1).

Принцип устройства гравиметра, имитируемого средствами C#, OpenGL

Рис. 1. Принцип устройства баллистического гравиметра

Зная начальную высоту hS, высот расположения датчика и время, которое прошло с начала падения до высоты расположения датчика, несложно вычислить ускорение g.

Число рассчитываемых значений ускорения g равно числу датчиков. Для получения ускорения g полученные по данным датчиков ускорения усредняются.

В работе разрабатывается приложение, имитирующее баллистический гравиметр.

Используемые программные средства

Язык программирования Visual C#, проект Window Forms Application. Графика реализована с помощью библиотек Tao.OpenGL.dll и Tao.Platform.Windows.dll. Эти библиотеки нетрудно найти в интернете.

Для подключения библиотек в Solution Explorer (рис. 2) добавляется ссылка (References - правая кнопка мыши Add Reference).

Solution Explorer: добавление ссылок на Tao.OpenGL.dll и Tao.Platform.Windows.dll

Рис. 2. Добавление ссылки

Выбираемые ссылки показаны на рис. 3.

Solution Explorer: выбор ссылок на Tao.OpenGL.dll и Tao.Platform.Windows.dll

Рис. 3. Выбор ссылок Tao.OpenGL.dll и Tao.Platform.Windows.dll

Область графического вывода добавляется в форму после выбора Tollbox - General - simpleOpenGlControl (рис. 4).

Tollbox - General - simpleOpenGlControl

Рис. 4. Добавление в форму области графического вывода

В рассматриваемом проекте эта область имеет имя GM (рис. 5)

Задание имени элемента simpleOpenGlControl

Рис. 5. Имя области графического вывода

Интерфейс пользователя

Позволяет задать начальную высоту, число датчиков и высоту их расположения (рис. 6).

Форма C#-проекта

Рис. 6. Интерфейс пользователя

Образ падающего тела (зеленый прямоугольник) устанавливается на начальной высоте. После задания числа датчиков и указания высоты их расположения можно нажать на кнопку "Пуск". Тело начинает падать, время прохождения датчика фиксируется в форме в строке задания высоты датчика (рис. 7).

Отображение результатов эксперимента в форме

Рис. 7. Можно рассчитать ускорение g

Датчик фиксирует время, когда нижняя граница тела достигает высоты расположения датчика.

По полученным данным рассчитывается ускорение g, значение вводится в поле "Ускорение" и нажимается кнопка "Проверить". В случае удачи выводится сообщение "Верно".

Если установлен флажок "Тест", то приложение само рассчитает ускорение g и отобразит его в поле "Ускорение".

Если нажать на кнопку "О программе", то появится следующая информация:

Проведение эксперимента.
  1. Задать начальную высоту и число датчиков.
  2. Задать высоту расположения датчиков.
  3. Нажать "Пуск".
  4. По данным датчиков рассчитать ускорение свободного падения.
  5. Ввести результат в поле "Ускорение" и нажать кнопку "Проверить".

Реализация

Анимация падения тела обеспечивается объектом timer, который в программе срабатывает каждые 10 мс. При срабатывании таймера вызываются процедуры Fall и Draw. Первая моделирует падение тела, а вторая отображает текущую сцену.

Объект Timer добавляется в проект в результате выполнения цепочки ToolBox - Components - Timer. Меню ToolBox.
Если оно отсутствует, можно показать посредством меню VIEW - ToolBox, или нажав Ctrl+Alt+X. Таймер отображается под формой, рис. 8, хотя и перетаскивается в форму проекта.

Расположение объекта Timer

Рис. 8. Добавление объекта Timer

Полный код формы приложения:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;
// OpenGL
using Tao.OpenGl;
using Tao.Platform.Windows;

namespace openGL
{
    public partial class Form1 : Form
    {
        float hStrt = 0; // Начальная высота
        float hCrrnt = 0; // Текущая высота
        float sec = 0; // Время падения
        float g = 9.81f; // Ускорение свободного падения, м/с^2
        bool click = false;
        float W = 50, H = 100; // Параметры матрицы проецирования

        public Form1()
        {
            InitializeComponent();
            GM.InitializeContexts();
        }

        private void GM_Load(object sender, EventArgs e)
        {
            Gl.glMatrixMode(Gl.GL_PROJECTION); // Текущей стала матрица проецирования
            Gl.glLoadIdentity();
            Gl.glOrtho(-W, W, 0, H, -1, 1);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
            Gl.glShadeModel(Gl.GL_FLAT); // Отказ от интерполяции цветов (GL_FLAT)
            Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_FILL); // Заливка (GL_FILL) полигонов
            timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Fall(ref hCrrnt); // Падение тела
            Draw(hCrrnt); // Отображение текущей сцены
        }

        private void Fall(ref float hCrrnt)
        {
            if (click)
            {
                int nsV = (int)nSensors.Value; // Число датчиков
                float cf = 1.004f; // Поправочный коэффициент
                float shV1 = (float)sh1.Value; // Высота установки первого датчика
                float shV2 = (float)sh2.Value;
                float shV3 = (float)sh3.Value;
                float shV4 = (float)sh4.Value;
                hCrrnt = hStrt - 0.5f * g * sec * sec;
                if (hCrrnt > 0f)
                {
                    sec += timer1.Interval / 1000f; // Время, прошедшее с начала падения тела
                    // Время падения, замеряемое датчиками
                    string t = Convert.ToString(Math.Round(sec, 2));
                    if (hCrrnt > cf * shV1) st1.Text = t;
                    if (hCrrnt > cf * shV2) st2.Text = t;
                    if (nsV > 2)
                    {
                        if (hCrrnt > cf * shV3) st3.Text = t;
                    }
                    else
                        st3.Text = "";
                    if (nsV > 3)
                    {
                        if (hCrrnt > cf * shV4) st4.Text = t;
                    }
                    else
                        st4.Text = "";
                    // Обновляем информацию о высоте, скорости и времени падения
                    crrntH.Text = Convert.ToString(Math.Round(hCrrnt, 2)) + " м";
                    label1.Text = Convert.ToString(Math.Round(g * sec, 2)) + " м/c";
                    label2.Text = Convert.ToString(Math.Round(sec, 2)) + " с";
                }
                else
                {
                    crrntH.Text = "0 м";
                    sec = 0;
                    hCrrnt = 0;
                    click = false;
                    nlbd(true);
                    if (checkBoxTest.Checked)
                    {
                        float t1 = float.Parse(st1.Text);
                        float t2 = float.Parse(st2.Text);
                        float g1 = 2.0f * (hStrt - shV1) / (t1 * t1);
                        float g2 = 2.0f * (hStrt - shV2) / (t2 * t2);
                        float gS = g1 + g2;
                        if (nsV > 2)
                        {
                            float t3 = float.Parse(st3.Text);
                            float g3 = 2.0f * (hStrt - shV3) / (t3 * t3);
                            gS += g3;
                        }
                        if (nsV > 3)
                        {
                            float t4 = float.Parse(st4.Text);
                            float g4 = 2.0f * (hStrt - shV4) / (t4 * t4);
                            gS += g4;
                        }
                        gS = gS / nsV;
                        textBox3.Text = Convert.ToString(Math.Round(gS, 2));
                    }
                }
            }
        }

        private void Draw(float y2)
        {
            float d = 5; // Высота прямоугольника-образа падающего тела
            // Массивы координат вершин прямоугольника (образа падающего тела)
            float[] v21 = { 0, y2 }, v22 = { d, y2 }, v23 = { d, y2 + d }, v24 = { 0, y2 + d };
            // Вершины линии нулевой высоты
            float[] v112 = { -W, 0 }, v122 = { W, 0 };
            Gl.glClearColor(1, 1, 1, 1); // Цвет фона
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT); // Очистка буфера цвета цветом фона
            Gl.glColor3f(0, 0, 1); // Текущий цвет синий
            // Линия нулевой высоты
            Gl.glLineWidth(6);
            Gl.glBegin(Gl.GL_LINES);
            Gl.glVertex2fv(v112);
            Gl.glVertex2fv(v122);
            Gl.glEnd();
            // Насечки по высоте
            int m = (int)(0.9 * H), r = 4;
            Gl.glLineWidth(1);
            Gl.glColor3f(1, 0, 0); // Текущий цвет красный
            Gl.glBegin(Gl.GL_LINES);
            while (m > 0)
            {
                if (r == 4)
                {
                    // Длинная насечка
                    Gl.glVertex2f(-2, m);
                    Gl.glVertex2f(2, m);
                    r = 0;
                }
                else
                {
                    // Короткая насечка
                    Gl.glVertex2f(-1, m);
                    Gl.glVertex2f(1, m);
                    r++;
                }
                m -= 1;
            }
            Gl.glEnd();
            Gl.glColor3f(0, 1, 0); // Текущий цвет
            Gl.glBegin(Gl.GL_QUADS); // Вывод прямоуольника - образа падающего тела
            Gl.glVertex2fv(v21);
            Gl.glVertex2fv(v24);
            Gl.glVertex2fv(v23);
            Gl.glVertex2fv(v22);
            Gl.glEnd();
            Gl.glFlush(); // Вывод в буфер кадра
            GM.Invalidate();
        }

        private void nlbd(bool tf)
        {
            textBox3.Enabled = tf;
            button1.Enabled = tf;
            button3.Enabled = tf;
            button4.Enabled = tf;
            button6.Enabled = tf;
        }

        // Кнопка "Проверить"
        private void button3_Click(object sender, EventArgs e)
        {
            float gPol = 0f; // Рассчитанное по результатам измерения ускорение свободного падения
            try
            {
                gPol = float.Parse(textBox3.Text);
            }
            catch
            {
                MessageBox.Show("Недопустимо");
                return;
            }
            float eps = 0.011f;
            if (Math.Abs(gPol - g) < eps)
                MessageBox.Show("Верно");
            else
                MessageBox.Show("Плохо");
        }

        // Кнопка "Пуск"
        private void button4_Click(object sender, EventArgs e)
        {
            click = true;
            textBox3.Text = "";
            nlbd(false);
        }

        // Кнопка "О программе"
        private void button6_Click(object sender, EventArgs e)
        {
            GM.Visible = !GM.Visible;
            label12.Visible = !label12.Visible;
            button1.Enabled = !button1.Enabled;
            button4.Enabled = !button4.Enabled;
            if (!textBox3.Enabled)
                button3.Enabled = false;
            else if (!GM.Visible)
                button3.Enabled = false;
            else
                button3.Enabled = true;
        }

        // Обработчик изменения числа датчиков
        private void nSensors_ValueChanged(object sender, EventArgs e)
        {
            int numberCheck = (int)nSensors.Value;
            sh4.Enabled = numberCheck > 3;
            sh3.Enabled = numberCheck > 2;
        }

        // Установка диапазонов изменения высоты датчиков. hSV - начальная высота
        private void setSensors(float hSV)
        {
            sh1.Maximum = Convert.ToDecimal(0.9 * hSV);
            sh1.Minimum = Convert.ToDecimal(0.7 * hSV);
            sh1.Value = sh1.Minimum;
            sh2.Maximum = Convert.ToDecimal(0.6 * hSV);
            sh2.Minimum = Convert.ToDecimal(0.5 * hSV);
            sh2.Value = sh2.Minimum;
            sh3.Maximum = Convert.ToDecimal(0.4 * hSV);
            sh3.Minimum = Convert.ToDecimal(0.3 * hSV);
            sh3.Value = sh3.Minimum;
            sh4.Maximum = Convert.ToDecimal(0.2 * hSV);
            sh4.Minimum = Convert.ToDecimal(0.1 * hSV);
            sh4.Value = sh4.Minimum;
        }

        // Начальные установки
        private void dflt(float hSV)
        {
            hStrt = hCrrnt = hSV;
            textBox3.Enabled = false;
            textBox3.Text = "";
            button3.Enabled = false;
            click = false;
            crrntH.Text = Convert.ToString(hSV) + " м";
            label1.Text = "0 м/c";
            label2.Text = "0 с";
            st1.Text = st2.Text = st3.Text = st4.Text = "";
            sec = 0;
        }

        // Обработчик изменения значения начальной высоты
        private void hS_ValueChanged(object sender, EventArgs e)
        {
            float hSV = (float)hS.Value;
            setSensors(hSV);
            dflt(hSV);
        }
        
        private void Form1_Load(object sender, EventArgs e)
        {
            float hSV = (float)hS.Value;
            setSensors(hSV);
            dflt(hSV);
        }

        // Кнопка "Закрыть"
        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

Заключение

На точность измерений отрицательно влияют дискретность изменения времени и округление. Для устранения этих влияний в процедуре Fall введен поправочный cf. Такой способ корректировки результата весьма груб и в перспективе должен быть замещен более тонкой настройкой.

Литература

  1. Боресков А. В. Графика трехмерной компьютерной игры на основе OpenGL. М.: ДИАЛОГ-МИФИ, 2004.

Список работ

Рейтинг@Mail.ru