Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

3-4

.js
Скачиваний:
22
Добавлен:
28.06.2021
Размер:
13 Кб
Скачать
//Вспомогательные функции:

// Экспоненциальная случайная переменная
function Exponentional(lambda) {
    const u = Math.random()
    return -Math.log(u) / lambda;
}

// функция интенсивности
function lamFunc(t) {
    return 2 + 2 / (t + 2);
}

// генерация Ts  
function PoissonNonuniform(start, lambda) {
    let t = start;
    while (true) {
        let u1 = Math.random();
        t = t - Math.log(u1) / lambda;

        let u2 = Math.random();
        //console.log(lamFunc(t) / lambda)
        if (u2 <= lamFunc(t) / lambda) {
            return t;
        }
    }
}


//Функции событый:

//прибытие клиента
function clientArrival(variables, out) {
    variables.t = variables.ta; // движение вдоль оси времени ко времени tA
    variables.Na += 1; // прибывших всего
    variables.n += 1; // клиентов в системе к моменту t

    // генерируем следующего клиента
    variables.ta = PoissonNonuniform(variables.t, variables.intensity) //Ts

    if (variables.n == 1) {
        variables.td = variables.t + Exponentional(variables.lam);
    }

    // запомнить время прибытия клиента Na
    out.A[variables.Na] = variables.t;

    out.summary.timeLine.push({
        i: "A" + variables.Na,
        t: variables.t
    });
    out.summary.sumOfClients += 1;
    out.summary.clientsAtEvent.push(variables.n);
}

// уход клиента
function clientLeft(variables, out) {
    variables.t = variables.td;
    variables.Nd += 1;
    variables.n -= 1;

    if (variables.n == 0) {
        variables.td = Infinity;
    } else {
        variables.td = variables.t + Exponentional(variables.lam);
    }

    // запомнить время ухода клиента Nd
    out.D[variables.Nd] = variables.t;

    out.summary.timeLine.push({
        i: "D" + variables.Nd,
        t: variables.t
    });
    out.summary.clientsAtEvent.push(variables.n);
}

// конец работы, но еще есть клиенты в системе
function clientLast(variables, out) {
    variables.t = variables.td;
    variables.Nd += 1;
    variables.n -= 1;

    if (variables.n > 0) {
        variables.td = variables.t + Exponentional(variables.lam);
    }

    // запомнить время ухода клиента Nd
    out.D[variables.Nd] = variables.t;

    out.summary.timeLine.push({
        i: "D" + variables.Nd,
        t: variables.t
    });
    out.summary.clientsAtEvent.push(variables.n);
}

// никаких клиентов не осталось
function clientOut(variables, out) {
    out.Tp = Math.max(variables.t - variables.T, 0);

    out.summary.clientsAtEvent.push(variables.n);
}

// Функции проверки возможности свершения событий:

// проверка: следующее событие – прибытие клиента
function canEventArrival(variables) {
    const { ta, td, T } = variables;
    return ta <= td && ta <= T;
}

// проверка: следующее событие – уход клиента
function canEventLeft(variables) {
    const { ta, td, T } = variables;
    return td < ta && td <= T;
}

// проверка: следующее событие происходит после времени T, но еще есть клиенты в системе
function canEventLast(variables) {
    const { ta, td, T, n } = variables;
    return (Math.min(ta, td) > T) && (n > 0);
}

// проверка: никаких клиентов не осталось, время работы закончилось
function canEventOut(variables) {
    const { ta, td, T, n } = variables;
    return (Math.min(ta, td) > T) && (n == 0);
}

// Имитация СМО с одним устройством
function smo(intensity, lmb, T) {
    let result = {
        D: [], // время ухода клиентов
        A: [], // время прибытия клиентов
        Tp: 0, // время после T, когда последний клиент уходит
        summary: {
            timeLine: [],
            sumOfClients: 0, // всего клиентов
            clientsAtEvent: [], // число клиентов в системе к моментам времени
            nonServiceTime: 0 
        },
        T: T // длина периода времени обслуживания
    }

    // переменные
    let variables = {
        t: 0, // время
        Na: 0, // число прибывших клиентов к моменту времени t
        Nd: 0, // число уходов  клиентов к моменту времени t
        n: 0, // число клиентов в системе к моменту времени t
        ta: 0, // время следующего прибытия клиента (после t); 
        td: Infinity, // время завершения работы устройства после обслуживания клиента (если нет, то бескон.)
        intensity: intensity,
        lam: lmb,
        T: T
    }

    variables.ta = Exponentional(lmb)
    variables.td = Infinity

    while (true) {
        /**
         * Случаи:
         * следующее событие – прибытие клиента
         * следующее событие – уход клиента
         * следующее событие происходит после времени T, но еще есть клиенты в системе
         * никаких клиентов не осталось, время работы закончилось
         */

        if (canEventArrival(variables)) {
            clientArrival(variables, result);
        } else if (canEventLeft(variables)) {
            clientLeft(variables, result);
        } else if (canEventLast(variables)) {
            clientLast(variables, result);
        } else if (canEventOut(variables)) {
            clientOut(variables, result);

            // конец обслуживания
            break;
        }
    }
    return result;
}



function showData() {
    let oneGen = smo(3, 7, 10);

    console.log("Клиенты:");
    console.log("i\t|\t A(i) \t\t|\t D(i) \t\t\t|\t D(i) - A(i)");
    console.log(`${''.padEnd(4, '-')}|${''.padEnd(15, '-')}|${''.padEnd(19, '-')}|${''.padEnd(19, '-')}`);

    // время пользователя в системе
    let userInSystem = 0;

    for (var i = 0; i < oneGen.D.length; i++) {
        if (oneGen.A[i] == undefined)
            continue;
        console.log(`${i} \t|\t ${oneGen.A[i].toFixed(4)} \t|\t ${oneGen.D[i].toFixed(4)} \t\t|\t ${(oneGen.D[i] - oneGen.A[i]).toFixed(4)}`);
        userInSystem += oneGen.D[i] - oneGen.A[i];
    }

    console.log();
    console.log();
    console.log("Число клиентов в определнный момент времени:");
    console.log("Событие\t|\t Время \t\t|\tQ(t)");
    console.log(`${''.padEnd(8, '-')}|${''.padEnd(15, '-')}|${''.padEnd(8, '-')}`);
    let arrayOfA = [];
    let W = []; // время задержки клиента в очереди
    
    // для расчета среднего времени между поступлениями
    let arrival = {
        old: null,
        size: 0,
        sum: 0
    };

    // для расчета среднего числа клиентов в системе Q(T) (интеграл)
    let count = {
        old: null,
        sum: 0
    };
    let nonServiceTime = 0; // время незанятости

    for (var i = 0; i < oneGen.summary.timeLine.length; i++) {
        console.log(`${oneGen.summary.timeLine[i].i.padEnd(3, " ")} \t|\t ${oneGen.summary.timeLine[i].t.toFixed(4)} \t|\t ${oneGen.summary.clientsAtEvent[i]}`);

        // число клиентов в системе
        if (count.old != null) {
            // число клиентов на отрезок времени (частичная сумма, численный интеграл)
            count.sum += (oneGen.summary.timeLine[i].t - count.old) * oneGen.summary.clientsAtEvent[i];
        }
        count.old = oneGen.summary.timeLine[i].t;

        // если событие прибытия
        if (oneGen.summary.timeLine[i].i.includes("A")) {
            // если первый клиент
            if (i == 0) {
                nonServiceTime = oneGen.summary.timeLine[i].t;
            
                // если не первый и предыдущий не занят был момент
            } else if (oneGen.summary.clientsAtEvent[i - 1] == 0) {

                // прибавляем время простоя
                nonServiceTime = oneGen.summary.timeLine[i].t - oneGen.summary.timeLine[i - 1].t;
            }

            // время между поступлениями
            if (arrival.old != null) {
                arrival.sum += oneGen.summary.timeLine[i].t - arrival.old;
                arrival.size = arrival.size + 1;
            }
            arrival.old = oneGen.summary.timeLine[i].t;
        }

        // если событие прибытия и не занято
        if (oneGen.summary.timeLine[i].i.includes("A") && oneGen.summary.clientsAtEvent[i] <= 1) {
            W.push({ i: oneGen.summary.timeLine[i].i.replace("A", ""), t: 0 })

            // иначе для прибытия если занято
        } else if (oneGen.summary.timeLine[i].i.includes("A")) {
            // сохраняем событие отдельно в очередь
            arrayOfA.push({ 
                i: oneGen.summary.timeLine[i].i.replace("A", ""), 
                t: oneGen.summary.timeLine[i].t 
            })
        }
        
        // если событие ухода клиента
        if (oneGen.summary.timeLine[i].i.includes("D") && arrayOfA.length != 0) {
            // изымаем из очереди и заносим время ожидания
            let elemA = arrayOfA.shift();
            W.push({ 
                i: elemA.i, 
                t: (oneGen.summary.timeLine[i].t - elemA.t) 
            });
        }
    }

    console.log();
    console.log("Время ожидания в очереди для каждого клиента: ");
    console.log("Клиент \t|\t Время в очереди");
    console.log(`${''.padEnd(8, '-')}|${''.padEnd(20, '-')}`);
    for (var i = 0; i < W.length; i++) {
        console.log(`${W[i].i.padEnd(3, " ")} \t|\t ${W[i].t.toFixed(4)}`);
    }

    console.log(); console.log();

    console.log("Статистики:");
    console.log("Число клиентов N = " + oneGen.summary.sumOfClients);
    console.log("Cреднее время, в течение которого клиент проводит в системе St = " + (userInSystem / oneGen.summary.sumOfClients).toFixed(4));
    console.log("Среднее время между поступлениями = " + (arrival.sum / arrival.size).toFixed(4));

    const WSum = W.map(el => el.t).reduce((a, b) => a + b, 0);
    console.log("Среднее время обслуживания = " + ((userInSystem - WSum) / oneGen.summary.sumOfClients).toFixed(4));
    console.log("Cредняя задержка клиентов в очереди W(T) = " + (WSum / oneGen.summary.sumOfClients).toFixed(4));
    console.log("Среднее число клиентов в очереди Q(T) = " + (count.sum / oneGen.T).toFixed(4));
    console.log("Коэффициент занятости устройства обслуживания rho(T) = " + ((oneGen.T - nonServiceTime) / oneGen.T).toFixed(4));
    console.log(`Длительность моделируемого периода = ${oneGen.T} ч.`);

    console.log();
    console.log("Время после T, когда последний клиент уходит (Tp) = " + oneGen.Tp.toFixed(4));

    //TpObs(2000);
}

//оценка Tp - время после T, когда ушел последний клиент
function TpObs(n) { 
    let sum = 0;
    for (let i = 0; i < n; i++) {
        sum += smo(3, 2, 10).Tp;
    }
    const tp = sum / n
    console.log(`Среднее Tp при ${n} испытаниях = ${tp.toFixed(4)}`);
}

showData();