Автор: Пользователь скрыл имя, 10 Января 2014 в 12:16, курсовая работа
Целью данной курсовой работы является разработка имитационной модели с регулярным входным потоком, отсутствующей очередью и естественным отсчетом времени т.е моделирование работы больничной палаты. Основой для разработки модели в данной курсовой работе является метод имитационного моделирования. Так же курсовая работа предполагает создание программы на языке C++, обеспечивающей ввод исходной информации, ее обработку, реализацию алгоритма имитации процесса и выдачу необходимой информации.
1. Введение………………………………………………………………………3
2. Моделирование систем массового обслуживания…………………………5
2.1 Структура и параметры эффективности и качества функционирования СМО………………………………………………………………………………5
2.2 Классификация СМО и их основные элементы………………...…………6
2.3 Процесс имитационного моделирования…………………………………12
3. Описание моделируемой системы……………………………………...…..16
3.1 Модельное время……………………………………………………….…..17
3.2 Используемые классы и объекты……………...………………….……….17
3.3 События и методы………………………………………………….………19
4. Программная реализация на С++…. ………………………………….……21
5. Анализ результатов работы программы……………………………....……35
6. Заключение……………….……………………………………………...…..38
7. Список использованной литературы…………………………………….…39
Листинг программы файл 10.h. Описание классов
#include<cstdio>
#include<cstdlib>
#include<ctime>
#define _USE_MATH_DEFINES
#include<cmath>
using namespace std;
#include "List.h"
#include "erlang.h"
#include "normal.h"
#include "random.h"
FILE *que; //файл для сбора статистики о длине очереди
FILE *sojourn; //файл для сбора статистики о времени пребывания
//в системе
int entered=0; //счетчик поступлений
int completed=0; //счетчик обслуженных заявок
int completed1=0; //счетчик заявок, не возвращавшихся в очередь
int completed2=0; //счетчик заявок, возвращавшихся в очередь
float ro_ave=0; //переменная
для подсчета коэффициента
//станков
float que_ave=0; //переменная для подсчета средней длины очереди
float soj_ave=0; //переменная для подсчета среднего времени пребывания
//в системе
long int total; //счетчик модельного времени
class Client
{
int id; //уникальный идентификатор
int time; //текущее время пребывания в системе
int to_serve; //остаточное время обслуживания
int interrupt; //признак возврата в очередь
protected:
static int counter; //счетчик заявок
public:
friend class Machine;
Client();
};
int Client::counter=0; //инициализация статического поля данных вне класса
Client::Client() //конструктор
{
counter++;
id=counter;
time=0;
interrupt=0;
to_serve=-1;
}
class Machine
{
const static int volume=1;
const static int input_rate=1;
const static int serve_median=30;
const static int serve_offset=6;
const static int set_median=21;
const static int set_offset=9;
const static int break_median=20;
const static int break_offset=2;
const static int repair_rate=133;
const static int repair_stages=3;
ListNode<Client> *queue; //очередь
Client **serving; //обслуживаемые заявки
int *to_serve; //текущее время до окончания обслуживания
int *to_setting; //текущее время до окончания наладки
int *to_break; //оставшееся время безаварийной работы
int *to_repair; //текущее время до окончания ремонта
int to_arrival; //время до прибытия новой заявки
int q_length; //текущая длина очереди
public:
Machine();
~Machine();
void Arrival();
void Complete(int i);
void Breakage(int i);
void Repair_End(int i);
void Set_End(int i);
int Busy();
int FirstAvail();
void run();
};
//Поиск доступного станка. Доступным считается станок, находящийся
//в состоянии простоя
int Machine::FirstAvail()
{
for(int i=0;i<volume;i++)
if ((serving[i]==NULL)&&(to_
return(i);
return(-1);
}
int Machine::Busy() //подсчет количества занятых станков
{
int k=0;
for(int i=0;i<volume;i++)
if (serving[i]!=NULL) k++;
return(k);
}
//Конструктор. Исходное
Machine::Machine()
{
queue=NULL;
//Выделение памяти под массивы
serving=new Client *[volume];
to_serve=new int[volume];
to_setting=new int[volume];
to_break= new int[volume];
to_repair= new int[volume];
to_arrival=(int)(get_exp(
if (to_arrival==0) to_arrival=1;
//Инициализация массивов
for(int i=0;i<volume;i++)
{
to_serve[i]=-1;
to_setting[i]=-1;
to_break[i]=(int)(get_normal(
if (to_break[i]==0) to_break[i]=1;
to_repair[i]=-1;
serving[i]=NULL;
}
q_length=0;
}
Machine::~Machine()
{
for(int i=0;i<volume;i++)
if (serving[i]!=NULL) delete serving[i];
delete [] serving;
delete[] to_serve;
delete[] to_setting;
delete[] to_break;
delete[] to_repair;
while(queue) queue=ListDelete<Client>(
}
void Machine::Arrival() //поступление новой заявки
{
int k;
Client *ptr=NULL;
ListNode<Client> *ptr1=NULL;
//Разыгрываем новую
to_arrival=(int)(get_exp(
if (to_arrival==0) to_arrival=1;
entered++; //инкремент счетчика поступлений
ptr=new Client(); //создание новой заявки
k=FirstAvail();
if (k==-1) //поставить поступившую заявку на обслуживание
//невозможно
{
ptr1=new ListNode<Client>(ptr, NULL);
if (queue==NULL) queue=ptr1;
else ListAdd<Client>(queue, ptr1);
q_length++;
}
else //новую заявку сразу ставим на обслуживание
//на k-й станок
{
serving[k]=ptr;
to_serve[k]=(int)get_normal(
if (to_serve[k]==0) to_serve[k]=1;
}
return;
}
void Machine::Complete(int i) //завершение обслуживания на i-м станке
{
completed++;
to_serve[i]=-1;
if (serving[i]->interrupt==0) completed1++;
else completed2++;
//запись статистики
fprintf(sojourn, "%.3f\n", ((float)serving[i]->time)/60);
soj_ave=soj_ave*(1-1.0/
delete serving[i];
serving[i]=NULL;
//Станок переходит в состояние наладки
to_setting[i]=get_uniform(
return;
}
void Machine::Breakage(int i) //поломка i-го станка
{
int k;
k=FirstAvail();
if (k==-1)
{
serving[i]->to_serve=to_serve[
serving[i]->interrupt=1;
//Заявка "от станка" заносится в голову очереди
queue=new ListNode<Client>(serving[i],
q_length++;
}
else
{
serving[k]=serving[i];
to_serve[k]=to_serve[i];
}
//Вышедший из строя станок переходит в состояние ремонта
serving[i]=NULL;
to_serve[i]=-1;
to_repair[i]=(int)(get_
if (to_repair[i]==0) to_repair[i]=1;
to_break[i]=-1;
return;
}
void Machine::Repair_End(int i) //завершение ремонта i-го станка
{
to_repair[i]=-1;
if (q_length==0) return; //очередь пуста, ставить на обслуживание
//Очередь не пуста, заявку из головы очереди ставим на отремонтированный //станок
serving[i]=queue->Data();
if (serving[i]->to_serve>0) //эта заявка ранее уже обслуживалась
{
to_serve[i]=serving[i]->to_
serving[i]->to_serve=-1;
}
else to_serve[i]=(int)get_normal(
if (to_serve[i]==0) to_serve[i]=1;
queue=queue->Next(); //сдвиг очереди
q_length--;
//Разыгрываем новое время безаварийной работы
to_break[i]=(int)(get_normal(
if (to_break[i]==0) to_break[i]=1;
}
void Machine::Set_End(int i) //завершение наладки i-го станка
//Код этого метода такой
же, как и код предыдущего, только
время //безаварийной работы
{
to_setting[i]=-1;
if (q_length==0) return;
serving[i]=queue->Data();
if (serving[i]->to_serve>0)
{
to_serve[i]=serving[i]->to_
}
else to_serve[i]=(int)get_normal(
if (to_serve[i]==0) to_serve[i]==1;
q_length--;
queue=queue->Next();
}
void Machine::run() //диспетчер
{
int i;
ListNode<Client> *ptr=NULL;
//Фиксируем сломавшиеся станки
for(i=0;i<volume; i++)
{
if (serving[i]!=NULL) to_break[i]--;
if (to_break[i]==0) Breakage(i);
}
if (to_arrival>0) to_arrival--;
if (to_arrival==0) Arrival();
//Осуществляем, если нужно,
переходы станков в новые
for(i=0;i<volume; i++)
{
if (serving[i]!=NULL) to_serve[i]--;
if (to_serve[i]==0) Complete(i);
if (to_setting[i]>0) to_setting[i]--;
if (to_setting[i]==0) Set_End(i);
if (to_repair[i]>0) to_repair[i]--;
if (to_repair[i]==0) Repair_End(i);
}
//Инкремент времени
//...в очереди
ptr=queue;
while(ptr)
{
ptr->Data()->time++;
ptr=ptr->Next();
}
//...и обслуживающихся
for(i=0;i<volume;i++)
if (serving[i]!=NULL) serving[i]->time++;
//Запись статистики
fprintf(que, "%d\n", q_length);
que_ave=que_ave*(1-1.0/(
ro_ave=ro_ave*(1-1.0/(total+
}
Листинг программы файл List.h
template <class Type> //это постоянная «заставка»
class ListNode {
private:
ListNode<Type> *next; //указатель на следующий элемент списка
Type *data;
public:
ListNode(Type *d, ListNode<Type> *n); //конструктор
~ListNode();
Type *Data();
ListNode<Type> *Next();
void PutNext(ListNode<Type> *n); //метод для записи указателя
void Print();
};
template <class Type>
ListNode<Type>::ListNode(Type *d, ListNode<Type> *n) : next(n), data(d){
}
template <class Type>
ListNode<Type>::~ListNode(){
delete data;
}
template <class Type>
Type *ListNode<Type>::Data(){
return data;
}
template <class Type>
ListNode<Type> *ListNode<Type>::Next(){
return next;
}
template <class Type>
void ListNode<Type>::PutNext(
next=n;
}
template <class Type>
void ListNode<Type>::Print(){
data->Print(); //предпологается наличие метода Print() для класса
}
//Описание класса-шаблона
завершено, далее идут функции-
//не с отдельным элементом, а со всеми списком
template <class Type>
void ListAdd(ListNode<Type> *head, ListNode<Type> *li) {
ListNode<Type> *old, *v;
for (v=head; v!=NULL; v=v->Next())
old=v;
old->PutNext(li); //добавляем в след за найденым хвостом новый элемент списка
}
template <class Type>
ListNode<Type> *ListDelete(ListNode<Type> *head, ListNode<Type> *li) {
ListNode<Type> *old, *o1;
if (li==head){
//удаляемый элемент может быть головой списка
o1=head->Next();
delete li;
return o1;
}
//Удаляемый элемент не являеться головой списка. Голова остаеться прежняя
for (ListNode<Type>* v=head; v!=li; v=v->Next())
//поиск элемента
old=v;
o1=li->Next();
old->PutNext(o1);
//предшествующий элеиент
теперь «видит» элемент
//за удаленным
delete li;
return head;
}
//печать всех элементов списка с головой head
template <class Type>
void ListPrint(ListNode<Type> *head){
for (ListNode<Type>* v=head; v!=NULL; v=v->Next())
v->Print();
}
template <class Type>
int ListCount(ListNode<Type> *head){
int i; i=0;
for (ListNode<Type>* v=head; v!=NULL; v=v->Next()){
v->Print();
i++;
}
return i;
}
Листинг программы файл random.h
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
float get_exp(float mu) //генератор случайных чисел, распределенных
//экспоненциально
{
int r_num; float root, right;
r_num=rand();
right=((float)r_num)/(RAND_
root=-log(1-right)/mu;
return(root);
}
int get_uniform(int a, int 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_
//Константа 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)*(
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;
root=A/(pow(1-right, (float)1.0/B)); /*вычисление значения обратной функции*/
return(root);
}
Листинг программы файл normal.h
#include<cstdio>
#include<cmath>
#include<cstdlib>
float get_normal(float mean, float disp, float eps);
float simpson(float A, float B, float mean, float disp);
float equ(float bottom_bound, float top_bound, float mean, float disp, float almost_all, float eps, float right);
float function(float mean, float disp, float x);
float get_normal(float mean, float disp, float eps)
{
int r_num;
float root, bottom_bound, top_bound, almost_all, right;
/*вычисление конечных аппроксимаций пределов интегрирования в соответствии с заданной точностью*/
bottom_bound=mean-disp*sqrt(-
top_bound=mean+disp*sqrt(-log(
/*вычисление интеграла в этих пределах*/
almost_all=simpson(bottom_
r_num=rand();
right=(float)r_num/32768;
root=equ(bottom_bound, top_bound, mean, disp, almost_all, eps, right);