Курсовая. Моделирование работы порта

Сдавался/использовалсяВолгоград, 2005 Руководитель: А.А. Теткин
Загрузить архив:
Файл: Моделирование работы порта.doc.zip (159kb [zip], Скачиваний: 1) скачать

ФГОУ СПО «Волгоградский технологический коледж»

«Проект защитил

с оценкой »

А.И Сухинин

30.05.05

Моделирование работы порта

Курсовой проект

КП 11. 230105. 51. 0232 ПЗ

Разработчик А.И. Сухинин

30.05.05

Рук.проекта А.А. Теткин

30.05.05

Содержание

1. Введение

2. Имитационное моделирование

3. Теория массового обслуживания

4. Описание системы

4.1 Модельное время

4.2 Классы и объекты

4.2.1Класс Tanker

4.2.3Класс Tug

4.2.4Класс Port

4.2.2Производный класс Tanker4

4.3 События и методы

5. Программная реализация алгоритма

6. Анализ результатов работы программы

7. Заключение

8. Список использованной литературы

ЕСЛИ НУЖНА ПРОГРАММА НА С++ ОБРАЩАЙТЕСЬ: saneek93@mail.ru

Оформление и правка возможна

1. Введение

Описание реальных отношений между экономическими объектами и производственными процессами наиболее рационально и в полной мере осуществляется с помощью моделей имитационного типа.

Термин имитационное моделирование означает, что речь идет о моделях с помощью, которых нельзя вычислить или предсказать результат и поэтому с их помощью проводиться вычислительный эксперимент при заданных исходных данных.

Метод имитационного моделирования дает возможность широкого использования математического аппарата и вычислительной техники для исследования хода экономических и производственных процессов .

Таким образом, сущность имитационного моделирования состоит в том, что с помощью ЭВМ воспроизводится поведение исследуемой системы, а исследователь, управляя ходом процесса и анализируя получаемые результаты, делает выводы о ее свойствах и качестве поведения. Поэтому под имитацией следует понимать численный метод проведения на ЭВМ экспериментов с алгоритмами, описывающими поведение системы и определения интересующих нас функциональных характеристик.

Имитационное моделирование является экспериментальной и прикладной методологией, имеющей целью:

    описать поведение систем; построить теории и гипотезы, которые могут объяснить наблюдаемое поведение; использовать эти теории для предсказания будущего поведения системы, т.е. тех воздействий, которые могут быть вызваны изменениями в системе или изменениями способов ее функционирования.

Целью данной курсовой работы является разработка имитационной модели очереди с разнотипными заявками т.е модели работы порта. Основой для разработки модели в данной курсовой работе является метод имитационного моделирования. Так же курсовая работа предполагает создание программы на языке C++, обеспечивающей ввод исходной информации, ее обработку, реализацию алгоритма имитации процесса и выдачу необходимой информации.

2. Имитационное моделирование

Имитационное моделирование — метод, позволяющий строить модели, описывающие процессы так, как они проходили бы в действительности. Такую модель можно «проиграть» во времени как для одного испытания, так и заданного их множества. При этом результаты будут определяться случайным характером процессов. По этим данным можно получить достаточно устойчивую статистику.

Имитационное моделирование — это метод исследования, при котором изучаемая система заменяется моделью, с достаточной точностью описывающей реальную систему и с ней проводятся эксперименты с целью получения информации об этой системе. Экспериментирование с моделью называют имитацией (имитация — это постижение сути явления, не прибегая к экспериментам на реальном объекте).

Имитационное моделирование — это частный случай математического моделирования. Существует класс объектов, для которых по различным причинам не разработаны аналитические модели, либо не разработаны методы решения полученной модели. В этом случае математическая модель заменяется имитатором или имитационной моделью.

Имитационным моделированием иногда называют получение частных численных решений сформулированной задачи на основе аналитических решений или с помощью численных методов.

Имитационная модель — логико-математическое описание объекта, которое может быть использовано для экспериментирования на компьютере в целях проектирования, анализа и оценки функционирования объекта.

Возникновение теории управления запасами можно связать с работами Ф.Эджуорта и Ф. Харриса, появившимися в конце XIX – начале XX вв., в которых исследовалась простая оптимизационная модель определении экономичного размера партии поставки для складской системы с постоянным равномерным расходом и периодическим поступлением хранимого продукта.
Запасами называется любой ресурс на складе, который используется для удовлетворения будущих нужд. Примерами запасов могут служить полуфабрикаты, готовые изделия, материалы, различные товары, а также такие специфические товары, как денежная наличность, находящаяся в хранилище. Большинство организаций имеют примерно один тип системы планирования и контроля запасов. В банке используются методы контроля за количеством наличности, в больнице применяются методы контроля поставки различных медицинских препаратов.

К имитационному моделированию прибегают, когда:

  • дорого или невозможно экспериментировать на реальном объекте;
  • невозможно построить аналитическую модель: в системе есть время, причинные связи, последствие, нелинейности, стохастические (случайные) переменные;
  • необходимо сымитировать поведение системы во времени.

Цель имитационного моделирования состоит в воспроизведении поведения исследуемой системы на основе результатов анализа наиболее существенных взаимосвязей между ее элементами или другими словами — разработке симулятора (англ. simulation modeling) исследуемой предметной области для проведения различных экспериментов.

Имитационное моделирование позволяет имитировать поведение системы во времени. Причём плюсом является то, что временем в модели можно управлять: замедлять в случае с быстропротекающими процессами и ускорять для моделирования систем с медленной изменчивостью. Можно имитировать поведение тех объектов, реальные эксперименты с которыми дороги, невозможны или опасны. С наступлением эпохи персональных компьютеров производство сложных и уникальных изделий, как правило, сопровождается компьютерным трёхмерным имитационным моделированием.

3. Теория массового обслуживания

Предметом теории массового обслуживания является количественная сторона процессов, связанных с массовым обслуживанием.

Целью теории является разработка математических методов отыскания основных характеристик процессов массового обслуживания, для оценки качества функционирования обслуживающей системы.

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

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

Задачей теории массового обслуживания является отыскание функциональных зависимостей величин, характеризующих качество функционирования обслуживающей системы, от характеристик входящего потока, параметров, характеризующих возможности одного обслуживающего аппарата, и способов организации всей обслуживающей системы в целом. Качество функционирования системы существенно зависит от того, как организовано управление процессом обслуживания, поэтому задача отыскания количественных характеристик организации управления является очень важной.

В области промышленного производства приходится очень часто сталкиваться с задачами массового обслуживания. Так, например, массовое обслуживание имеет место при обеспечении заводами-поставщиками и фабриками предприятий-потребителей и торговой сети своей продукцией. Обеспечение производства сырьем также носит характер массового обслуживания.

Организация взаимодействия между цехами в пределах предприятия представляет собой пример задач того же типа, только на более низкой ступени. В масштабах цеха теория массового обслуживания начинается со снабжения цеха сырьем и заканчивается организацией обслуживания и ремонта станков.

Большое количество проблем, связанных с массовым обслуживанием, должно быть решено при производственном планировании. В этом случае затраты усилий на детальное изучение количественной стороны процессов планирования даст большой экономический эффект и позволит более глубоко проникнуться в природу этих процессов.

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

Использование методов теории может помочь также при осуществлении выбора лучшего, наиболее экономичного проекта из нескольких возможных.

Теория массового обслуживания поможет правильно организовать производство с целью наибольшего удовлетворения потребителей продукцией предприятия, являющейся выходящим потоком. Выяснение приоритетов потребителей должно осуществляться маркетинговыми службами с помощью анкетирования и опросов.

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

4.Описание системы

В африканском порту танкеры загружаются сырой нефтью, которую затем морским путем доставляют по назначению. Мощности порта позволяют загружать
на более трех танкеров одновременно. Танкеры, прибывающие в порт через каж-
дые 11 ± 7 ч, относятся к трем различным типам. Относительная частота появ-
ления танкеров данного типа и время, требуемое на их погрузку, приведены в
табл. 1. Относительную частоту следует понимать как вероятность того, что
прибывший танкер относится к данному типу.

Таблица 1. Характеристики типов танкеров

Тип

Относительная частота

Время погрузки, ч

1

0,25

18 ±2

2

0,55

24 ±3

3

0,20

36 ± 4

В порту имеется один буксир, услугами которого пользуются все танкеры при
причаливании и отчаливании. Причаливание и отчаливание занимает по одному
часу, причем, если в услугах буксира нуждаются сразу несколько танкеров, при-
оритет отдается операции причаливания.

Судовладелец предлагает дирекции порта заключить контракт на перевозку нефти в Великобританию и обеспечить выполнение условий контракта с помощью5 танкеров особого, четвертого типа, для погрузки которых требуется 21 ± 3 ч.После погрузки танкер отчаливает и следует в Великобританию, там разгружается и затем снова возвращается в африканский порт для погрузки. Время цикла
обращения танкера, включая время разгрузки, составляет 240 ± 24 ч.
Фактором, осложняющим перевозку нефти, являются штормы, которым подвер-
гается порт. Интервал времени между штормами распределен экспоненциально
с математическим ожиданием 48 ч, причем шторм продолжается 4 ± 2 ч. Во вре-
мя шторма буксир не работает.

Перед заключением контракта руководство порта решило определить влияние,
которое окажут пять дополнительных танкеров на функционирование порта.
Выводы предлагается сделать по результатам имитации работы порта в течение
одного года (8760 ч) при условии заключения предлагаемого контракта Оцени-
ваемые величины — время пребывания в порту дополнительных танкеров и уже
работающих танкеров трех типов.

4.1 Модельное время

За единицу модельного времени примем 1 мин, чтобы не связывать себя мало-
вероятным предположением, что все события занимают промежутки времени,
кратные одному часу. Интервал времени между штормами будем генерироватьтак: (int)(get_exp(mu)*60), гдеmu = 1/48 = 0,021. Для генерации равномерного рас-
пределения (для интервалов между прибытиями танкеров, времени погрузки и
цикла обращения) будем использовать функцию getuniform( ), которая разыгры-
вает абсолютное значение отклонения от среднего, а затем с вероятностью 0,5
прибавляет его к среднему либо вычитает из него. Этот способ позволяет умень-
шить в два раза значение делителя при взятии остатка, а значит, снизить ошиб-
ку, возникающую из-за того, что 32 768 не делится нацело на этот делитель.

4.2 Классы и объекты

Продолжаем наращивать арсенал приемов, используемых для объектного представления динамических систем. Рассмотрим особенности поставленной задачи:

  • Буксир имеет две разных очереди на обслуживание — на причаливание и наотчаливание. Заявки из очереди на отчаливание обслуживаются только в томслучае, если очередь на причаливание пуста.
  • Система соединяет в себе свойства как открытой, так и замкнутой. Количество заявок первых трех типов является переменной неограниченной величиной, так как они поступают из внешнего входного потока и, будучи обслуженными, покидают систему, после чего их дальнейшая судьба не отслеживается.Количество же заявок дополнительного, четвертого типа является постоянным, каждая из них периодически возвращается на обслуживание в систему,и за ними нужно продолжать следить в промежутках между периодами обслуживания (путешествие из Африки в Великобританию на разгрузку нефтии обратно). В связи сэтим заявки первых трех типов будем называть неименованными, а заявки четвертого типа — именованными.

Три типа неименованных заявок, разумеется, можно описать одним классом,
так как они различаются только значениями своих неизменяемых полей дан-
ных — частотой встречаемости и временем обслуживания. Так как неименован-
ные заявки постоянно находятся под контролем некоторого обслуживающего
устройства — буксира или порта, — метод run( ) для них не нужен, их постоянно
будут «вести» другие объекты, а после выхода из порта они как объекты переста-
ют существовать. В противоположность этому именованные заявки после выхо-
да из порта пускаются «в самостоятельное плавание», продолжая существоватьв качестве полноправных объектов системы. В это время они сами должны сле-
дить за собой и в конце концов зафиксировать момент следующего прибытия на
погрузку. Очень показательна разница между механизмами фиксации прибытия
неименованных и именованных заявок. Неименованные заявки поступают из
случайного входного потока, поэтому время их прибытия разыгрывается с помо-
щью ГСЧ, а само событие инициируется принимающей стороной — буксиром.
Прибытие же именованной заявки буксиром не разыгрывается - она сама дает
знать о прибытии в порт, посылая буксиру соответствующее сообщение.

Указанные различия в поведении говорят о том, что неименованные и именованные заявки одним классом представлять нельзя, так как эти различия являются
существенными. Для отображения поведения именованной заявки нам понадо-
бятся и дополнительные поля данных, и дополнительные методы. Но и описы-
вать их совершенно разными классами тоже нехорошо.Дело в том, чтопосле причаливания как те, так и другие заявки будут находиться в общей очере-
ди на погрузку. Но если в очереди будут заявки разных классов, какой
же тогда класс подставлять в шаблон в качестве значения параметра, коим как
раз и является имя класса? Получается, что и один класс, и два разных класса —
неудовлетворительные решения.

Ответ приходит сам собой — конечно же, следует применить наследование. Внимательное изучение того, что происходит в системе и что нужно отразить в программе, позволяет сделать вывод, что все поля данных и методы неименованныхзаявок покрываются именованными, последние же расширяются некоторым
множеством дополнительных полей и методов, например run(), а некоторые ме-
тоды переопределяются (например, count()). Поэтому базовым классом будет
класс неименованных заявок, а производным от него расширенный класс име-
нованных заявок. Проблема с «разнотипностью элементов» списка тоже решает-
ся наилучшим образом. Напомним, что в качестве данных в элементе списка вы-
ступает не сам объект, а указатель на него, поэтому в качестве параметра
шаблона можно задать имя базового класса — неименованных заявок. По прин-
ципу подстановкиуказатель на объект производного класса является и указателем на объект базового класса, поэтому указатель на именованнуюзаявку — объект производного класса — можно смело заносить в элемент списка.

Конкретизируем рассуждения, перечислив поля базового класса Tankerи производного класса Tanker4.

4.2.1Класс Tanker

Неизменяемые поля данных:

  • уникальный идентификатор объекта; можно назначить равным текущемузначению счетчика прибытий;
  • тип танкера (1, 2 или 3);
  • среднее значение времени обслуживания на погрузке;
  • максимальное отклонение от среднего значения.

Изменяемые поля данных:

  • Время, проведенное в системе на текущий момент, начиная от постановкив очередь к буксиру на причаливание;
  • код текущего состояния (1 — в очереди на причаливание, штормит; 2 — в очереди на причаливание, шторма нет, 3 — причаливание; 4 — в очереди на погрузку; 5 — погрузка; 6 — в очереди на отчаливание, штомит; 7 - в очередина отчаливание, шторма нет; 8 — отчаливание).

4.2.2Производный класс Tanker4

Неизменяемые поля данных:

  • среднее значение времени в пути на разгрузку и обратно (14 400 мин);
  • максимальное отклонение от среднего значения (1440 мин);
  • связь с объектом Буксир для посылки ему сообщения о своем прибытии.

Изменяемые поля данных:

  • добавляется еще одно возможное значение кода текущего состояния: 9 — в путина разгрузку или обратно;
  • время до прибьргия на причаливание; поле данных имеет смысл лишь для состояния 9.

По аналогии с предыдущими задачами буксир и порт должны быть объявлены
«друзьями» танкера. Интересный нюанс заключается в том, что дружествен-
ность нужно отдельно объявить и в производном классе Тапкег4, так как по пра-
вилам С++ она не наследуется.

Довольно много полей данных приходится вводить для класса Буксир (Tug). Этосвязано с тем, что буксир является связующим звеном между танкерами и пор-
том, а кроме того следует учитывать еще и влияние штормов.

4.2.3Класс Tug

Неизменяемые поля данных:

  • среднее значение интервала времени между прибытиями танкеров первых трехтипов (660 мин);
  • максимальное отклонение от среднего значения (420 мин);
  • длительность причаливания и отчаливания (60 мин);
  • средняя продолжительность шторма (240 мин);
  • максимальное отклонение от среднего значения (120 мин);
  • параметр экспоненциального распределения для интервала времени между штормами (0,021);
  • указатель на объект класса Portдля взаимодействия с ним.
    Изменяемые поля данных:
  • время до следующего прибытия танкера одного из трех типов;
  • время до окончания причаливания;
  • время до окончания отчаливания;
  • очередь танкеров на причаливание;
  • очередь танкеров на отчаливание;
  • причаливающий (отчаливающий) танкер;
  • текущая длина очереди на причаливание (вычисляемое поле);
  • текущая длина очереди на отчаливание (вычисляемое поле);
  • время до начала следующего шторма;
  • время до окончания шторма.

4.2.4Класс Port

Класс Portмоделируется как обычный многоканальный узел обслуживания
с общей очередью.

Неизменяемые поля:

  • количество терминалов для погрузки (3);
  • указатель на объект класса Tug.

Изменяемые поля:

  • очередь танкеров на погрузку;
  • массив указателей на обслуживаемые в данный момент танкеры;
  • массив значений времени, оставшегося до окончания погрузки на каждом изтерминалов;
  • текущая длина очереди (вычисляемое поле).

4.3 События и методы

Танкеры выполняют в системе роль заявок, поэтому они не имеют моделирующих методов — все события, происходящие с ними, принимаются и обрабаты-
ваются объектами-серверами. Для буксира можно выделить следующие события и связанные с ними методы:

  1. Начало шторма. Метод не имеет параметров.
  2. Окончание шторма. Метод не имеет параметров.
  3. Прибытие танкера четвертого типа на причаливание. Метод имеет параметр —указатель на прибывший танкер.
  4. Прибытие танкера одного из первых трех типов на причаливание. Метод неимеет параметров.
  5. Один из танкеров закончил погрузку и требует отчаливания. Метод имеет параметр — указатель на танкер.
  6. Окончание отчаливания. Метод не имеет параметров, так как отчалившийтанкер доступен через поле данных самого буксира.
  7. Окончание причаливания. Метод не имеет параметров, так как причалившийтанкер доступен через поле данных самого буксира.

Коротко остановимся на особенностях некоторых методов. Методы 3 и 4 описывают одно и то же событие, но их алгоритмические реализации различаются по
причине уже упоминавшегося существования различий между именованными и
неименованными заявками. В методе 4 необходимо создать новый временный
объект базового класса Tankerи разыграть время до прибытия следующего танке-
ра. В методе 3 этого делать не нужно, так как прибывший объект уже существует
в системе и доступ к нему мы получаем через передаваемый параметр. Эти два
метода могут иметь одно название, что допускается правилами С++, так как их
сигнатуры различаются. Конечно, методы 3 и 4 можно было бы объединить и в
один, передавая в одном из случаев NULL-указатель и осуществляя внутри соот-
ветствующую проверку параметра. Но такой подход скрывал бы принципиаль-
ные различия между обработкой двух вариантов прибытия танкеров, которые
здесь, наоборот, хотелось бы подчеркнуть.

В методе 5 в качестве параметра может быть передан указатель на танкер любоготипа — как указатель на объект базового класса.

Отметим, что финальной частью методов 2, 6 и 7 является одно и то же дейст-
вие — выбор в одной из очередей первого танкера и постановка его на обслужи-
вание. Этот общий фрагмент кода для исключения повторений удобно выделить
в отдельный метод, который мы назвали choice( ).

Для объекта Portсобытий всего два:

  • прибытие очередного танкера. Метод имеет один параметр — указатель наприбывший танкер — и вызывается буксиром из метода 7;
  • завершение погрузки. Метод имеет один параметр — номер терминала, который завершил погрузку, — и вызывает метод 5 для буксира.

5. Программная реализация алгоритма

Присоздания имитационной модели очереди с разнотипными заявками (работа порта) был выбран язык программирования C++ и написана программа на этом языке, позволяющая в полной мере отразить функционирование системы.

Листинг программы файл 6.h. Описание протоколов классов

#include

#include

#include

#include

using namespace std;

#include "List.h"

#include "random.h"

FILE *q_tugIn; //файл для сбора статистики о длине очереди

//на причаливание

FILE *q_tugOut; //файл для сбора статистики о длине очереди

//на отчаливание

FILE *q_loading; //файл для сбора статистики о длине очереди

//на погрузку

FILE *sojourn; //файл для сбора статистики о времени пребывания

//в порту

float q_tugInAve=0; //переменная для подсчета средней длины очереди

//на причаливание

float q_tugOutAve=0; //переменная для подсчета средней длины очереди

//на отчаливание

float q_loadAve=0; //переменная для подсчета средней длины очереди

//на погрузку

float soj_Ave=0; //переменная для подсчета среднего времени

//пребывания на погрузке

float soj1_Ave=0; //переменная для подсчета среднего времени

//пребывания на погрузке для танкеров первых

//трех типов

float soj2_Ave=0; //переменная для подсчета среднего времени

//пребывания на погрузке для танкеров

//четвертого типа

long int ro_tug=0L; //переменная для подсчета загрузки буксира

float ro_port=0; //переменная для подсчета загрузки порта

long int entered=0L; //счетчик общего числа поступлений

long int completed=0L; //счетчик отчаливших танкеров

long int completed1=0L; //счетчик отчаливших танкеров первых трех типов

long int completed2=0L; //счетчик отчаливших танкеров четвертого типа

long int total; //счетчик тактов модельного времени

//базовыйкласс

class Tanker{

public:

long int id; //идентификатортанкера

int type; //номертипа

int median; //среднее время погрузки

int offset; //максимальное отклонение

int minutes; //текущее время пребывания на погрузке

int state; //текущеесостояние

friend class Tug;

friend class Port;

Tanker(); //конструктор

//Метод Print() удобно объявить виртуальным, например, для обхода любой из //очередей и распечатки ее содержимого, так как в очереди могут находиться //танкеры любого типа

virtual void Print();

};

//Производныйкласс

class Tanker4: public Tanker{

const static int median_path=14400; //14400 минут=240 часов - среднее

//время обращения танкера четвертого

//типа

const static int offset_path=1440; //24 часа - максимальное отклонение

//от среднего для времени обращения

//танкера четвертого типа

int to_arrival; //время до прибытия пустого танкера на причаливание

void *t; //связь с буксиром

public:

friend class Tug;

friend class Port;

Tanker4(int i);

void putTug(Tug *a);

void run();//диспетчер

virtual void Print();

};

//КлассБуксир

class Tug{

const static int arr_median=660; //660 минут=11 часов - среднеевремямежду //прибытиямитанкеровпервыхтрехтипов

const static int arr_offset=420; //7 часов - максимальное отклонение

//от среднего для интервалов между

//прибытиями танкеров первых трех типов

const static int time_path=60; //1 час - длительность причаливания

//и отчаливания

const static int storm_median=240; //4 часа - средняя длительность шторма

const static int storm_offset=120; //2 часа - максимальное отклонение

//от среднего для длительности шторма

const static int storm_mu=21; //1/48, где 48 часов - средняя

//длительность "бесштормового"

//интервала времени

int to_arrival; //время до прибытия танкера типов 1,2,3

int to_in; //время до окончания причаливания

int to_out; //время до окончания отчаливания

ListNode *queue_in; //очередь на причаливание

ListNode *queue_out; //очередь на отчаливание

Tanker *serving; //обслуживаемый танкер

int que_inLength; //длина очереди на причаливание

int que_outLength; //длина очереди на отчаливание

int to_sStart; //время до начала шторма

int to_sEnd; //время до окончания шторма

void *p; //указатель на порт

public:

Tug();

void stormStart(); //начало шторма

void stormEnd(); //окончание шторма

void Arrival_Sea(Tanker4 *t); //прибытие танкера четвертого типа

void Arrival_Sea(); //прибытие танкера типов 1,2,3

void Arrival_coast(Tanker *t); //танкер требует отчаливания

void Departure(); //окончание отчаливания

void Arrival(); //окончание причаливания

void run(); //диспетчер

void putPort(Port *a);

void choice(); //выбор танкера для обслуживания

void Print();

};

//КлассПорт

class Port{

const static int volume=3;

ListNode *queue; //очередьнапогрузку

Tanker **serving; //загружаемыетанкеры

int *to_serve; //времядоокончанияпогрузки

int q_length; //длина очереди

void *t; //указатель на буксир

public:

Port();

~Port();

void Arrival(Tanker *a); //прибытиетанкера

void Complete(int i); //завершениепогрузки

void putTug(Tug *a);

void Print();

int FirstAvail();

int Busy();

void run(); //диспетчер

};

Tanker::Tanker(){

int r;

id=entered;

minutes=0;

//Разыгрывание типа танкера

r=rand()%100+1;

if (r>=25) type=1;

else if (r<=55) type=2;

else type=3;

switch(type){

case 1: median=1080; offset=120; break;

case 2: median=1440; offset=180; break;

case 3: median=2160; offset=240; break;

}

}

void Tanker::Print(){

switch(state){

case 1: printf("Танкер № %ld типа %d находится в очереди на причаливание. Штормитn", id, type); break;

case 2: printf("Танкер № %ld типа %d находится в очереди на причаливание. Шторма нетn", id, type); break;

case 3: printf("Танкер № %ld типа %d причаливаетn", id, type); break;

case 4: printf("Танкер № %ld типа %d находится в порту в очереди на погрузкуn", id, type); break;

case 5: printf("Танкер № %ld типа %d грузится в портуn", id, type); break;

case 6: printf("Танкер № %ld типа %d находится в очереди на отчаливание. Штормитn", id, type); break;

case 7: printf("Танкер № %ld типа %d находится в очереди на отчаливание. Шторма нетn", id, type); break;

case 8: printf("Танкер № %ld типа %d отчаливаетn", id, type); break;

}

}

//Начальное состояние танкера четвертого типа - 9

Tanker4::Tanker4(int i){

id=i;

minutes=0;

state=9;

type=4;

to_arrival=get_uniform(median_path, offset_path);

median=1260;

offset=180;

}

void Tanker4::putTug(Tug *a){

t=a;

}

void Tanker4::Print(){

switch(state){

case 1: printf("Танкер № %ld типа %d находится в очереди на причаливание. Штормитn", id, type); break;

case 2: printf("Танкер № %ld типа %d находится в очереди на причаливание. Шторма нетn", id, type); break;

case 3: printf("Танкер № %ld типа %d причаливаетn", id, type); break;

case 4: printf("Танкер № %ld типа %d находится в порту в очереди на погрузкуn", id, type); break;

case 5: printf("Танкер № %ld типа %d грузится в портуn", id, type); break;

case 6: printf("Танкер № %ld типа %d находится в очереди на отчаливание. Штормитn", id, type); break;

case 7: printf("Танкер № %ld типа %d находится в очереди на отчаливание. Шторма нетn", id, type); break;

case 8: printf("Танкер № %ld типа %d отчаливаетn", id, type); break;

case 9: printf("Танкер № %ld типа %d находится в путиn", id, type); break;

}

}

void Tanker4::run()

{

if (state==9) to_arrival--;

//Танкер прибыл из Великобритании и сообщает об этом буксиру

if (to_arrival==0) ((Tug*)t)->Arrival_Sea(this);

}

//В начальном состоянии буксир свободен, очереди пусты

Tug::Tug(){

to_arrival=get_uniform(arr_median, arr_offset);

serving=NULL;

to_in=-1;

to_out=-1;

queue_in=NULL;

queue_out=NULL;

que_inLength=0;

que_outLength=0;

to_sStart=(int)(get_exp((float)(storm_mu/1000))*60);

if (to_sStart==0) to_sStart=1;

to_sEnd=-1;

}

void Tug::choice(){

//Очередь на причаливание не пуста, ей - приоритет

if (que_inLength>0){

to_in=time_path;

que_inLength--;

serving=queue_in->Data(); //головуочереди - наобслуживание

queue_in=queue_in->Next(); //продвижениеочереди

}

//Заявок на причаливание нет, а на отчаливание - есть

else if (que_outLength>0){

to_out=time_path;

que_outLength--;

serving=queue_out->Data();

queue_out=queue_out->Next();

}

return;

}

void Tug::stormStart(){

to_sStart=-1;

to_sEnd=get_uniform(storm_median, storm_offset);

}

void Tug::stormEnd(){

to_sEnd=-1;

to_sStart=(int)(get_exp((float)(storm_mu/1000))*60);

if (to_sStart==0) to_sStart=1;

choice();

}

void Tug::Arrival_Sea() //прибытиетанкератипов 1,2,3

{

to_arrival=get_uniform(arr_median, arr_offset);

entered++;

Tanker *ptr=new Tanker(); //создаемновыйтанкер

//Шторма нет, буксир свободен, танкер сразу идет на причаливание

if ((to_sEnd==-1)&&(serving==NULL)){

serving=ptr;

to_in=time_path;

serving->state=3;

return;

}

//Танкер ставится в очередь

que_inLength++;

ListNode *ptr1=new ListNode(ptr, NULL);

if (queue_in==NULL) queue_in=ptr1;

else ListAdd(queue_in, ptr1);

//Назначение танкеру номера состояния в зависимости от наличия шторма

if (to_sEnd>0) ptr->state=1;

else ptr->state=2;

return;

}

void Tug::Arrival_Sea(Tanker4 *t){

entered++;

t->to_arrival=-1;

if ((to_sEnd==-1)&&(serving==NULL)){

serving=t;

to_in=time_path;

serving->state=3;

return;

}

que_inLength++;

ListNode *ptr1=new ListNode(t, NULL);

if (queue_in==NULL) queue_in=ptr1;

else ListAdd(queue_in, ptr1);

if (to_sEnd>0) t->state=1;

else t->state=2;

return;

}

voidTug::Arrival_coast(Tanker *t) //прибытие танкера на отчаливание

{

if ((to_sEnd==-1)&&(serving==NULL)) //шторманет, буксирсвободен

{

serving=t;

to_out=time_path;

serving->state=8;

return;

}

que_outLength++;

ListNode *ptr1=new ListNode(t, NULL);

if (queue_out==NULL) queue_out=ptr1;

else ListAdd(queue_out, ptr1);

if (to_sEnd>0) t->state=6;

else t->state=7;

return;

}

void Tug::Departure(){

to_out=-1;

//Фиксация времени пребывания в порту отбывающего танкера

fprintf(sojourn,"%.3fn", (float)serving->minutes/60);

completed++;

//Пересчетсреднеговременипребывания

soj_Ave=soj_Ave*(1-1.0/completed)+(float)(serving->minutes)/completed;

//Отбываеттанкертипов 1,2,3

if (serving->type<4){

completed1++;

soj1_Ave=soj1_Ave*(1-1.0/completed1)+(float)(serving->minutes)/completed1;

//Объект для неименованной заявки удаляется из системы

delete serving;

}

else //отбывает танкер четвертого типа

{

completed2++;

soj2_Ave=soj2_Ave*(1-1.0/completed2)+(float)(serving->minutes)/completed2;

serving->state=9;

//Отправляем танкер четвертого типа в Великобританию

((Tanker4*)serving)->to_arrival=get_uniform(((Tanker4*)serving)->median_path, ((Tanker4*)serving)->offset_path);

//Сброс времени пребывания в порту

serving->minutes=0;

}

serving=NULL;

//Пока отчаливали, начался шторм. Буксир отдыхает

if (to_sEnd>0) return;

//Шторманет. Выбираем следующий танкер на обслуживание

choice();

}

void Tug::Arrival() {

to_in=-1;

//Сообщаем в порт о прибытии танкера на погрузку

((Port*)p)->Arrival(serving);

serving=NULL;

//Пока причаливали, начался шторм. Буксир отдыхает

if (to_sEnd>0) return;

choice();

}

void Tug::run(){

int k;

if (to_sStart>0) to_sStart--;

if (to_sStart==0) stormStart();

if (to_sEnd>0) to_sEnd--;

if (to_sEnd==0) stormEnd();

if (to_arrival>0) to_arrival--;

if (to_arrival==0) Arrival_Sea();

if (to_in>0) to_in--;

if (to_in==0) Arrival();

if (to_out>0) to_out--;

if (to_out==0) Departure();

ListNode *ptr=queue_in;

//Инкремент времени пребывания для всех танкеров, которые в данный момент //контролирует буксир

while(ptr!=NULL) {

ptr->Data()->minutes++;

ptr=ptr->Next();

}

ptr=queue_out;

while(ptr!=NULL){

ptr->Data()->minutes++;

ptr=ptr->Next();

}

if (serving!=NULL) serving->minutes++;

//Запись статистики - один раз в час

if ((total+1)%60==0){

k=(total+1)/60;

fprintf(q_tugIn,"%dn", que_inLength);

q_tugInAve=q_tugInAve*(1-1.0/k)+((float)que_inLength)/k;

fprintf(q_tugOut,"%dn", que_outLength);

q_tugOutAve=q_tugOutAve*(1-1.0/k)+((float)que_outLength)/k;

}

if (serving!=NULL) ro_tug++;

}

void Tug::putPort(Port *a){

p=a;

}

void Tug::Print(){

if (to_sStart==-1)

printf("Буксир не работает из-за штормаn");

else if (to_in>0)

printf("Буксирпомогаетпричалитьтанкерутипа %dn", serving->type);

else if (to_out>0)

printf("Буксирпомогаетотчалитьтанкерутипа %dn", serving->type);

else

printf("Буксир простаивает, так как некого обслуживатьn");

}

//Конструктор для класса Port

Port::Port(){

int i;

queue=NULL;

serving=new Tanker *[volume];

to_serve=new int[volume];

for(i=0;i

serving[i]=NULL;

to_serve[i]=-1;

}

q_length=0;

}

//Деструктор для класса Port

Port::~Port(){

delete[] to_serve;

delete [] serving;

}

void Port::Arrival(Tanker *t){

int i;

//Проверяем, есть ли свободный терминал

i=FirstAvail();

if (i!=-1) //есть, стразу ставим танкер на погрузку

{

serving[i]=t;

to_serve[i]=get_uniform(t->median, t->offset);

serving[i]->state=5;

}

else //нет, ставим танкер в очередь

{

q_length++;

ListNode *ptr=new ListNode(t, NULL);

if (queue==NULL) queue=ptr;

else ListAdd(queue, ptr);

t->state=4;

}

}

void Port::Complete(int i){

//Отправляемзагруженныйтанкеркбуксиру

((Tug*)t)->Arrival_coast(serving[i]);

to_serve[i]=-1;

serving[i]=NULL;

if (queue==NULL) return;

//Очередь не пуста, ставим на освободившийся терминал новый танкер

serving[i]=queue->Data();

to_serve[i]=get_uniform(serving[i]->median, serving[i]->offset);

serving[i]->state=5;

queue=queue->Next();

q_length--;

}

void Port::run(){

int k;

//Проверка завершения обслуживания и инкремент времени пребывания для всех //танкеров, находящихся под контролем порта

for(int i=0;i

if (to_serve[i]>0) { serving[i]->minutes++; to_serve[i]--; }

if (to_serve[i]==0) Complete(i);

}

ListNode *ptr=queue;

while(ptr!=NULL){

ptr->Data()->minutes++;

ptr=ptr->Next();

}

//Запись статистики - 1 раз в час

if ((total+1)%60==0){

k=(total+1)/60;

fprintf(q_loading,"%dn", q_length);

q_loadAve=q_loadAve*(1-1.0/k)+((float)q_length)/k;

ro_port=ro_port*(1-1.0/k)+((float)Busy())/(k*volume);

}

}

void Port::Print(){

printf("В очереди на погрузку находятся %d танкеровn", q_length);

printf("Заняты погрузкой %d терминаловn", Busy());

for(int i=0;i

printf("%d-йтерминалобслуживаеттанкертипа %dn", i+1, serving[i]->type);

}

int Port::FirstAvail(){

for(int i=0;i

if (serving[i]==NULL) return(i);

return(-1);

}

int Port::Busy() //вычисление текущего количества занятых терминалов

{

int k=0;

for(int i=0;i

if (serving[i]!=NULL) k++;

return(k);

}

void Port::putTug(Tug *a){

t=a;

}

Листинг программы файл random.h

#include

#include

#include

float get_exp(float mu) {

//генератор случайных чисел, распределенных

//экспоненциально

intr_num; floatroot, right;

r_num=rand(); //получение случайного целогочисла

right=((float)r_num)/(RAND_MAX+1); //проекция на интервал (0;1)

root=-log(1-right)/mu; //вычисление значения обратной функции

return(root);

}

intget_uniform(inta, intb){ //Генерация равномерно распределенной величины a+b

int x, y;

x=rand()%(b+1);

y=rand()%2;

if (y==0) return(a-x);

return(a+x);

}

float get_triangle(float A, float B, float C){

int r_num; float root, right;

r_num=rand(); //получение случайного целого

//числа

right=((float)r_num)/(RAND_MAX+1); //проекция на интервал (0;1).

//Константа RAND_MAX=32767 (215-1) определена в cstdlib

if (right<(C-A)/(B-A)) root=A+sqrt(right*(B-A)*(C-A));

else root=B-sqrt((1-right)*(B-A)*(B-C));

return(root);

}

float get_pareto(float A, float B){

int r_num; float root, right;

r_num=rand(); //получение случайного целого числа

right=(float)r_num/RAND_MAX+1; //проекция на интервал (0;1)

root=A/(pow(1-right, (float) 1.0/B)); //вычисление значения обратной функции

return(root);

}

Листинг программы файл List.h

template //это постоянная «заставка»

//к класам и функциям

//c парметризированным типом

classListNode {

private:

ListNode *next; //указатель на следующий элемент списка

Type *data; //указатель на данные хранящиеся в элементе списка

public:

ListNode(Type *d, ListNode *n); //конструктор

~ListNode(); //деструктор

Type *Data(); //метод для чтения данных

ListNode *Next(); //метод для чтения указателя

//на следующий элемент

voidPutNext(ListNode *n); //метод для записи указателя

//на следующий элемент

voidPrint(); //печать содержимого элемента списка

};

template

ListNode::ListNode(Type *d, ListNode *n) : next(n), data(d){

}

template

ListNode::~ListNode(){

delete data;

}

template

Type *ListNode::Data(){

return data;

}

template

ListNode *ListNode::Next(){

return next;

}

template

void ListNode::PutNext(ListNode *n){

next=n;

}

template

void ListNode::Print(){

data->Print(); //предпологаетсяналичиеметода Print() длякласса

//имя которого будет подставленно в пользовательском коде

}

//Описание класса-шаблона завершено, далее идут функции-шаблона, работающие

//не с отдельным элементом, а со всеми списком

template

void ListAdd(ListNode *head, ListNode *li) {

//добавление нового элемента li в хвост списка с головой head

ListNode *old, *v;

//ищем внешний хвост списка

for (v=head; v!=NULL; v=v->Next())

old=v;

old->PutNext(li); //добавляем в след за найденым хвостом новый элемент списка

}

template

ListNode *ListDelete(ListNode *head, ListNode *li) {

//удаление элемента li из списка с голоыой head

//функция возвращает указатель на голову нового списка

//int j;

ListNode *old, *o1;

if (li==head){

//удаляемый элемент может быть головой списка

//в этом случае голова у списка меняется

o1=head->Next();

delete li;

return o1;

}

//Удаляемый элемент не являеться головой списка. Головаостаетьсяпрежняя

for (ListNode* v=head; v!=li; v=v->Next())

//поиск элемента предшедствующего удаляемому

old=v;

o1=li->Next();

old->PutNext(o1);

//предшествующий элеиент теперь «видит» элемент стоящий в списке вслед

//за удаленным

delete li;

returnhead;

}

//печать всех элементов списка с головой head

template

void ListPrint(ListNode *head){

for (ListNode* v=head; v!=NULL; v=v->Next())

v->Print(); //подсчет количества элементов в списке с головой head

}

template

int ListCount(ListNode *head){

int i; i=0;

for (ListNode* v=head; v!=NULL; v=v->Next()){

v->Print();

i++;

}

return i;

}

Листингпрограммыфункция main()

#include "stdafx.h"

#include "iostream"

#define N 525600 //количество минут в году

#define M 5 //количество танкеров четвертого типа

#define _CRT_SECURE_NO_WARNINGS

#include "6.h"

int main(){

int i;

Tanker4 **mas;

//Создание объектов Буксир и Порт

Port port;

Tug tug;

//Настройка их взаимодействия

port.putTug(&tug);

tug.putPort(&port);

mas=new Tanker4 *[M];;

q_tugIn=fopen("q_tugIn", "wt");

q_tugOut=fopen("q_tugOut", "wt");

q_loading=fopen("q_loading", "wt");

sojourn=fopen("sojourn", "wt");

srand((unsigned)time(0));

//Инициализация танкеров четвертого типа и настройка их взаимодействия

//сбуксиром

for(i=0;i

mas[i]=new Tanker4(i+1);

mas[i]->putTug(&tug);

}

//Основной цикл моделирования

for(total=0L;total

tug.run();

port.run();

for(i=0;i

mas[i]->run();

}

delete [] mas;

//Закрытие файлов сбора статистики

fclose(sojourn);

fclose(q_tugIn); fclose(q_tugOut); fclose(q_loading);

setlocale(LC_ALL, "Russian");

//Вывод на печать результатов эксперимента

cout << "Всего поступлений танкеров " << entered << endl;

cout << "Завершили цикл обслуживания в порту " << completed << endl;

cout << "Из них танкеров типов 1,2,3 - " << completed1 << endl;

cout << "Из них танкеров четвертого типа " << completed2 << endl;

cout << "Средняя длина очереди на причаливание " << q_tugInAve << endl;

cout << "Средняя длина очереди на отчаливание " << q_tugOutAve << endl;

cout << "Средняя длина очереди на погрузку " << q_loadAve << endl;

cout << "Среднее время пребывания на погрузке " << soj_Ave/60 << endl;

cout << "Среднее время пребывания на погрузке для танкеров типов 1,2,3 - " << soj1_Ave/60 << endl;

cout << "Среднее время пребывания на погрузке для танкеров четвертого типа - " << soj2_Ave/60 << endl;

cout << "Коэффициент загрузки буксира - " << ((float)ro_tug)/total << endl;

cout << "Коэффициент загрузки порта - " << ro_port << endl;

_gettch();

}

6.Анализ результатов работы программы

При отсутствии танкеров четвертого типа моделирование дает следующие ре-
зультаты:

Рис. 1. Снимок работы программы с отстсутствием танкеров 4-ого типа

  • всего поступлений в систему — 790 танкеров;
  • из них обслужено — 789 танкеров;
  • средняя длина очереди на причаливание — 0,004 танкера;
  • средняя длина очереди на отчаливание — 0,005 танкера;
  • средняя длина очереди на погрузку — 0,012 танкера;
  • среднее время пребывания на погрузке — 21,8 часа;
  • коэффициент загрузки буксира — 0,18;
  • коэффициент загрузки порта — 0,59.

Мы видим, что неиспользованные ресурсы системы довольно велики, и, видимо,контракт заключить стоит. Убедимся в этом. При добавлении пяти танкеров четвертого типа получаем:

  • всего поступлений в систему — 946;
  • из них завершили обслуживание — 944;
  • из них танкеров типов 1, 2, 3 — 784;
  • танкеров типа 4 — 160;
  • средняя длина очереди на причаливание — 0,027;
  • средняя длина очереди на отчаливание — 0,035;
  • средняя длина очереди на погрузку — 0,16;
  • среднее время пребывания на погрузке (для всех танкеров) — 23,68 ч;
  • среднее время пребывания на погрузке для танкеров типов 1, 2, 3 — 23,23 ч;
  • среднее время пребывания на погрузке для танкеров типа 4 — 25,88 ч;
  • коэффициент загрузки буксира — 0,22;
  • коэффициент загрузки порта — 0,72.

Рис. 2. Снимок работы программы с пятью танкерами 4-ого типа

Показатели выросли, но остались в пределах нормы, перегрузок нигде не воз-
никло.

Интересно проследить, как меняются показатели работы системы при дальнейшем увеличении количества М танкеров четвертого типа. Из графика, приведенного на рис. 3, видно, что среднее время пребывания танкеров в порту Тср увеличивается довольно медленно, пока М не превосходит 15. Далее T срначинает
увеличиваться стремительно и быстро выходит за разумные пределы. Следо-
вательно, заключать контракт на обслуживание более 15 танкеров нецелесо-
образно.

Рис. 3. Зависимость среднего времени пребывания в портуот количества танкеров четвертого типа

Рис. 4. Зависимость коэффициента загрузки буксира от количества танкров четвертого типа

Рис. 5. Зависимость коэффициента загрузки порта от количества танкеров четвертого типа

Из графика на рис. 3 можно сделать еще один вывод. Время обслуживания танкерабуксиром фиксировано и равно 2 ч, что составляет в общем-то небольшую долюдля значения Тср. Значит, потенциальным узким местом системы является погрузка в порту, где танкеры проводят все оставшееся время. Этот вывод подтверждают графики, изображенные на рис. 4 и 5.

Так, из графика, приведенного на рис. 4, видно, что загрузка буксира при увеличении М стремится асимптотически к некоторой не очень большой величине,равной приблизительно 0,3. А вот порт с ростом М быстро оказывается перегруженным, его загрузка стремится к единице.

7. Заключение

В результате выполнения курсовой работы были достигнуты следующие результаты:

    изучены метод имитационного моделирования экономических объектов; получены навыки проведения численных экспериментов на имитационных моделях экономических систем; приобретен опыт проведения анализа по результатам данных экспериментов на имитационной модели;

Список использованной литературы

    Труб И. И. «Объектно-ориентированное моделирование на С++»: Учебный курс.-СПб.:Питер, 2006.-411с.:ил.
  1. Варфоломеев В.И. «Алгоритмическое моделирование элементов экономических систем». - М.: Финансы и статистика, 2000г.
  2. Клейнрок Л. «Теория массового обслуживания.»-М.: Машиностроение,1979.-432 с.
  3. Прицкер А. «Введение в имитационное моделирование»-М.: Мир,1987.-644с.
  4. Емельянов А.А.,Власова Е.А., «Имитационное моделирование экономических процессов» - М. Финансы и статистика,2002.
  5. Дубров А.М., Лагоша Б.А., Хрусталев Е.Ю. Моделирование рискованных ситуаций в экономике и бизнесе. –М.: Финансы и статистика, 2004. -224 с. Князевская Н.В., Князевский В.С. Принятие рискованных решений в экономике и бизнесе. –М.: Контур, 1998. -160 с. Кремер Н.Ш. Исследование операций в экономике. –М.: Банки и биржи, 2003. -407 с. Шикин Е.В. Математические методы и модели в управлении. –М.: Финансы и статистика, 2002. -430 с.

Список электронных ресурсов

  1. Имитационное моделирование: Режим доступа:
  2. Теория массового обслуживания: Режим доступа:http://ru.wikipedia.org/wiki/Теория_массового_обслуживания
  3. Система массового обслуживания: Режим доступа:http://ru.wikipedia.org/wiki/Система_массового_обслуживания