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

 «Системы и сети связи с подвижными объектами».

Тема: «Голосовая радиопочта»

Часть 3 – Физический уровень уровень

                                                                                             Выполнила: 

                                                                                             студентка группы 319

                                                                                             Лукашова Е.В.

 

 

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

 

Основные требования к системе:

-off-line доставка сообщений: при отсутствии в сети адресата сообщение должно быть доставлено позже;

- возможность доставки голосовых сообщений абонентам других подобных сетей.

 

Исходные данные к проекту:

·         Максимальное количество абонентов в сети: 700;

·         Радиус зоны радиопокрытия: 5000 м;

·         Гарантируемая (минимальная) скорость передачи данных: 256Kбит/с;

·         Тип местности: городская застройка;

·         Вероятность ошибки на бит Pb: 5*10-7;

·         Мощность излучения подвижной станции Ризл :< 0.5 Вт ;

·         Рекомендуемая технология передачи: OFDM PR: 75%;

·         Диапазон частот, вид модуляции выбирается самостоятельно.



1.7. Построение результирующих иерархических моделей терминала и выделенных узлов сети (в соответствии с концепцией OSI) с отражением путей доставки служебных, так и информационных сообщений.


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

К Основный задачам, выполняемым на физическом уровне, относится сформирование необходимого для L2 уровня количество/тип ФК и обеспечение достоверной доставки битов по назначению.

Для выполнения задачи достоверной доставки применяются меры:

·         синхронизация;

·         помехоустойчивое кодирование;

·         модуляция;

·         применение технологии OFDM;

·         эквалайзинг.

 

На Рисунке 1 представлена результирующая иерархическая модель сети в соответствии с концепцией OSI


Рисунок1 - Иерархическая модель системы

Физический уровень – это самый нижний уровень системы, который отвечает за непосредственный передачу (прием) сигнала в (из) радиоканал(а). Основная задача уровня – сформировать необходимое для L2 уровня количество/тип ФК и обеспечить достоверную доставку битов по назначению

 

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

 

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

 

            С уровня принятия решений на физический уровень поступают результаты радиоизмерений (профиль передачи и мощность излучения). От канального уровня на физический поступают пакеты L2 и количество этих пакетов в одном сообщении. Этот набор пакетов L2 проходит через следующие процедуры: канальное кодирование, квадратурная модуляция, OFDM-модуляция и образует информационное поле сообщения физического уровня. На основе профиля передачи, поступившего от L3, типа сообщения, извлеченного из первого пакета L2 и значения количества пакетов в сообщении ФУ, поступившего от L2, формируется служебное поле. Служебное и информационное поля объединяются с заранее сформированной (а так же записанной в память, поскольку она всегда имеет одинаковый вид) преамбулой и образуют полное сообщение физического уровня. Оно усиливается до необходимого уровня и излучается в радиоканал.


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

2. Экспериментальная часть. Разработка и экспериментальное исследование программной модели канала передачи данных

 

2.1. Разработка и описание блок-схемы алгоритма модели

 

На рисунке2 и рисунке3 представлены блок схемы алгоритмов передающей и приемной части системы.



Рисунок2 - Блок-схема передающей части модели


Рисунок3 - Блок- схема приемной части модели


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


Программный модуль состоит из Matlab-функций имитирующих работу ФУ и КУ, функции предназначенной для непосредственного формирования OFDM-символов, функции для определения максимального СКО среди символов СКС принятого сигнала, а так же скрипта отражающего часть сценария работы сети, а именно - передача псевдослучайного сообщения трафика (состоящего из одного пакета) от терминала к точке доступа.

  • start.m – часть сценария работы сети, частично затрагивает работу канального уровня сети;
  • l2_func.m – функция отражающая работу канального уровня системы;
  • phy_lvl.m  функция отражающая работу физического уровня системы;
  • makeOfdmFrame.m  функция для формирования OFDM-символа;
  • IQ_maxSKO.m  функция для определения максимального СКО среди символов СКС принятого сигнала.
 Программный модуль формирует пакеты L2 и сообщение физического уровня согласно структурам рисунок4 и рисунок5 из предыдущих частей КР.

Рисунок4- Структуры сообщений канального и физического уровней


Рисунок5- Структура сигнала


Листинг №1 функции физического уровня

 


function [ L2_msgs_rcv msgType_rcv msgCount_rcv sigPower maxSKO errorFlag ] = phy_lvl( L2_msgs, msgCount, mProfile, SN, img, rMeasureFlag )
% L2_msgs - пакеты L2
% msgCount - количество передаваемых пакетов L2
% mProfile - профидь передачи 0 - QPSK 1 - QAM-16
% SN - ОСШ в КС, SN = 0 - моделирование прохождения через КС отключено
% img - показ графиков, 0 - выкл. 1 - вкл.
% rMeasure - вывод в консоль данных радиоизмерений на ФУ, 0 - выкл. 1 - вкл.

%== Физический уровень передатчика ==%
    global noninfSubcarriers;
    global Nc;
    global ampPilot;
    trell = poly2trellis( 7, [ 171 133 ] );
    errorFlag = 0;
% Список не информационных поднесущих в OFDM-символе
    noninfSubcarriers = [ 1 2 3 4 5 12 26 39 53 60 61 62 63 64 ];
% Размерность OFDM-символа
    Nc = 64;
% Определяем тип пакетов L2
    if all( L2_msgs( 6:9 ) == [ 0 0 0 0 ] )
        msgType = 0;
    else
        msgType = 1;
    end
    
%% Формирование служебного поля
% Выбор типа модуляции для служебного символа 
    mParam = modem.pskmod( 4 );
    mParam.inputtype = 'bit';
    mParam.SymbolOrder = 'gray';
    mParam.PhaseOffset = 0;
% Формирование служебного символа
    serviceMsg = zeros( 1, Nc );
% Информация о виде модуляции
    serviceMsg( 1 ) = mProfile;
% Информация о типе сообщения
    serviceMsg( 2 ) = msgType;         
% Кол-во пакетов в сообщении
    msgLength = dec2bin( msgCount, 8 );
    for i = 1:8
        serviceMsg( 2 + i ) = str2num( msgLength( i ) );
    end
% Помехоустойчивое кодирование
    serviceMsg_c = convenc( serviceMsg, trell );
% Перемежение
    serviceMsg_cai = randintrlv( serviceMsg_c, 534 );
% Квадратурная модуляция
    IQ_service = modulate( mParam, serviceMsg_cai' );
% Формирование OFDM символа
    symbol = ifft( IQ_service );
    ofdmFrame = [ symbol' ];
    
%% Определение профиля передачи
    if mProfile == 0
        mPos = 4;
        mParam = modem.pskmod( mPos );
        ampPreamb_short = 0.75; % КУ усиления для выравнивания уровня преамбулы к данным
        ampPreamb_long = 1; % КУ усиления для выравнивания уровня преамбулы к данным
        ampPilot = 2; % КУ для пилот сигнала
    else
        mPos = 16;
        mParam = modem.qammod( mPos );
        ampPreamb_short = 3; % КУ усиления для выравнивания уровня преамбулы к данным
        ampPreamb_long = 3; % КУ усиления для выравнивания уровня преамбулы к данным
        ampPilot = 4; % КУ для пилот сигнала
    end;
        
%% Работа над пакетами L2
% Определяем размер пакета L2 исходя из его типа
    if msgType == 1
        packLength = 200;
    else
        packLength = 400;
    end
    
    L2_msgs_cai = [];
    for pack = 1:msgCount
        packStart = ( pack - 1 ) * packLength + 1;
        L2_msg = L2_msgs( packStart:( packStart +  packLength - 1) );
    
%% Канальное кодирование
% Помехоустойчивое кодирование
       L2_msg_c = convenc( L2_msg, trell );
% Перемежение
       L2_msg_cai = randintrlv( L2_msg_c, 534 );
       L2_msgs_cai = [ L2_msgs_cai L2_msg_cai ];
    end

%% Модуляция (квадратурная и OFDM)  
% Размер передаваемого сообщения
    L2_msg_length = length( L2_msgs_cai );
% Количество поднесущих с информацией
    Nc_data = Nc - length( noninfSubcarriers ); % 50 поднесущих
% Количество бит на OFDM-символ
    symbolLength = Nc_data * log2( mPos );
% Требуемое количество OFDM-символов
    symbolCounter = ceil( L2_msg_length / symbolLength );
% Формирование блока незначащих битов
    symbolGarbage = zeros( 1, symbolCounter * symbolLength - L2_msg_length );   
% Cообщение канального уровня
    data = L2_msgs_cai;
% Выбор модуляции
    mParam.inputtype = 'bit';
    mParam.SymbolOrder = 'gray';
    mParam.PhaseOffset = 0;
% Добавление незначащих битов
    if ( symbolCounter - L2_msg_length / symbolLength ) == 0
        data = [ data ]';
    else
        data = [ data symbolGarbage ]';
    end
% Квадратурная модуляция
    IQ_signal = modulate( mParam, data );
% Формирование OFDM-символов и добавление служебного символа
    [ mof, OS, OSf, OSp ] = makeOfdmFrame( IQ_signal, symbolCounter );
    ofdmFrame = [ ofdmFrame mof ];
    
%% Формирование символов преамбулы
% Короткий символ преамбулы
    Preamb_shortline = sqrt( 13 / 6 )*[ 0 0 1+j 0 0 0 -1-j 0 0 0 1+j 0 0 0 -1-j 0 0 0 -1-j 0 0 0 1+j 0 0 0 0 0 0 -1-j 0 0 0 -1-j 0 0 0 ...
        1+j 0 0 0 1+j 0 0 0 1+j 0 0 0 1+j 0 0 ];   
    Preamb_shortSymb = ifft( Preamb_shortline );
% Выделение первых 16 отсчетов
    short = Preamb_shortSymb( 1:16 );
% Формирование 10 коротких символов преамбулы на основе выбранного набора
    Preamb_shortComplete = [ short short short short short short short short short short ];
% Длинный символ преамбулы
    Preamb_longline = [ 0 0 0 0 0 0 1 1 -1 -1 1 1 -1 1 -1 1 1 1 1 1 1 -1 -1 1 1 -1 1 -1 1 1 1 1 ...
        1 -1 -1 1 1 -1 1 -1 1 -1 -1 -1 -1 -1 1 1 -1 -1 1 -1 1 -1 1 1 1 1 0 0 0 0 0 0 ];
    Preamb_longSymb = ifft( Preamb_longline );
    Preamb_longComplete = [ Preamb_longSymb( 64 - 2 * 16 + 1:64 ) Preamb_longSymb Preamb_longSymb ];
% Окончательная сборка преамбулы (усиление чтобы выровнить уровень к уровню данных)
    Preamb_Full = [ ampPreamb_short * Preamb_shortComplete ampPreamb_long * Preamb_longComplete ];
    
 %% Сборка сообщения физического уровня
    l1Frame = [ Preamb_Full ofdmFrame ];

    if img == 1
        figure( 1 );
        plot( abs( l1Frame ) );
        grid on
        title( 'Временная реализация сообщения физического уровня' )
    end;

%% Задержка сигнала на псевдослучайное кол-во отсчетов (от 0 до 200)
    l1Frame_delay = [ zeros( 1, randi( 200 ) ) l1Frame ];    
    
%% AWGN-канал
    if SN ~= 0
        l1Frame_rcv = awgn( l1Frame_delay, SN, 'measured' );
    else
        l1Frame_rcv = l1Frame_delay;
    end    
    
%== Физический уровень приемника ==%
%% Синхронизация
% Подготовка окна    
    sync_rcv = zeros(1, length( l1Frame_rcv ) - length( Preamb_Full ) );
% Сдвиг и расчет СКО
    for i = 1: ( length( l1Frame_rcv ) - length( Preamb_Full ) )
       searchBlock = l1Frame_rcv( i: ( i - 1 + length( Preamb_Full ) ) );
       sync_rcv(i) = sum( abs( searchBlock - Preamb_Full).^2 );
    end
% Нахождение минимума СКО и соответственно, начала преамбулы  
    [ SKO_min Preamb_Start_rcv ] = min( sync_rcv );
% Определение окончания преамбулы   
    Preamb_End_rcv = Preamb_Start_rcv + length( Preamb_Full );

% Отображение графика    
    if img == 1
        figure( 4 );
        plot( sync_rcv );
        grid on
        title( 'СКО между двумя блоками: скользящим окном и преамбулой' )
    end;

% Измерение мощности принятого сигнала
    sig = l1Frame_rcv( Preamb_Start_rcv:end );
    sigPower = sum(abs(sig(:)).^2)/length(sig(:));
    if rMeasureFlag == 1
        display( 'Мощность принятого сигнала:' )
        disp( sigPower );
    end
    
%% Выделение полей
% Выделение преамбулы, сервисного поля и поля данных
    Preamb_Full_rcv = l1Frame_rcv( Preamb_Start_rcv:Preamb_End_rcv );
    symbol_rcv = l1Frame_rcv( ( Preamb_End_rcv ):( Preamb_End_rcv + 64 - 1 ) );
    ofdmFrame_rcv =  l1Frame_rcv( ( Preamb_End_rcv + 64 ):end );
    IQ_service_rcv = fft( symbol_rcv' );

%% Демодуляция
% Настройка вида модуляции сервисного поля 
    mParam = modem.pskdemod( 4 );
    mParam.SymbolOrder = 'gray';
    mParam.PhaseOffset = 0;
    mParam.OutputType = 'bit';
% Демодуляция сервисного поля
    serviceMsg_cai_rcv = demodulate( mParam, IQ_service_rcv );
% Деперемежение
    serviceMsg_c_rcv = randdeintrlv( serviceMsg_cai_rcv, 534 );
% Декодирование по Витерби
    serviceMsg_rcv = vitdec( serviceMsg_c_rcv, trell, 7, 'cont', 'hard' );
% Определение профиля передачи
    mProfile_rcv = serviceMsg_rcv( 8 );
% Определение типа принятого сообщения
    msgType_rcv = serviceMsg_rcv( 9 );
% Определение длинны принятого сообщения
    for i = 1:6
        msgLength_rcv( i ) = num2str( serviceMsg_rcv( 9 + i ) );
    end
    msgCount_rcv = bin2dec( msgLength_rcv );
% Если количество принятых сообщений получилось равным 0, считаем что оно
% равно 1. В этом случае уже ясно, что сообщение принято не верно
% (сообщение есть, а пакетов в нем ноль? - абсурд), однако возможно
% "угадать" количество пакетов L2. Если не угадаем у КУ не сойдется
% контрольная сумма и он все равно сделает вывод о том что сообщение
% принято неверно.
    if msgCount_rcv == 0
        msgCount_rcv = 1;
    end
    
% Определение профиля передачи поля данных
    if mProfile_rcv == 1
        mPos_rcv = 16;
        mParam = modem.qamdemod( mPos_rcv );
    else
        mPos_rcv = 4;
        mParam = modem.pskdemod( mPos_rcv );
    end;
    mParam.SymbolOrder = 'gray';
    mParam.PhaseOffset = 0;
    mParam.OutputType = 'bit';
    
% Определение типа сообщения
    if msgType_rcv == 1
       packLength_rcv = 400;
    else
       packLength_rcv = 800;
    end    
    
% Выполняем выделение OFDM символов из общего потока
    IQ_signal_rcv = [];
% Список поднесущих с информацией
    infSubcarriers = [ 6:11 13:25 27:38 40:52 54:59 ];
    pilotSubcarriers = [ 1 5 12 26 39 53 60 64 ];
    equSubcarrLine = 1:64;
    OSr = [];
    OSpr = [];
    for i = 0:( length( ofdmFrame_rcv ) / 68 ) - 1    
        IQ_sig = ofdmFrame_rcv( ( 5:68 ) + i * 68 ); % Удаление префикса
        OSr = [ OSr; IQ_sig ];   
        IQ_sign = fft( IQ_sig ); % Переход к частотной области
        pilot_rcv = IQ_sign( pilotSubcarriers ); % Выделение пилот-сигналов
        pilot_rcv( 1 ) = pilot_rcv( 2 ); % Дублирование крайних пилот сигналов на "концы" символа
        pilot_rcv( 8 ) = pilot_rcv( 7 );
        equInterpol = interp1( pilotSubcarriers, abs( pilot_rcv ), equSubcarrLine, 'pchip' ); % Интерполяция АЧХ канала
        OSpr = [ OSpr; IQ_sign ];
        IQ_sign_equalazied = IQ_sign ./ ( equInterpol ./ ampPilot ); % Непосредственно эквалайзер
        IQ_signal_rcv = [ IQ_signal_rcv IQ_sign_equalazied( infSubcarriers ) ]; % Формирование потока данных
    end;
% Квадратурная демодуляция закодированного и перемеженного пакета L2
    data_rcv = demodulate( mParam, IQ_signal_rcv );
% Определяем максимальное СКО среди IQ-символов
    [ maxSKO ] = IQ_maxSKO( IQ_signal_rcv, data_rcv, mPos_rcv );
    if rMeasureFlag == 1
        display( 'Максимальное СКО среди символов СКС принятого сигнала:' )
        disp( maxSKO );
    end
% Убираем лишние биты. Лишние биты появляются в двух случаях:
% 1) Их специально добавили на этапе передачи для полного
%    заполнения OFDM-символа;
% 2) Возникла ошибка в приеме полей типа, модуляции или длинны сообщения
%    в этом случае не совпадает фактическая и ожидаемая длинна принятого
%    информационного поля и если эти значения не уравнять возникнет ошибка
%    на этапе канального декодирования.
% Рассчитываем ожидаемую длинну информационного поля
    infoLength_rcv = ( packLength_rcv * msgCount_rcv );
% Рассчитываем фактически принятую длинну информационного поля
    data_size_rcv = size( data_rcv );
    dataLength_rcv = data_size_rcv( 1 ) * data_size_rcv( 2 );
% Если фактическая больше - уравниваем путем удаления лишнего.    
    if infoLength_rcv < dataLength_rcv
        for i =  dataLength_rcv:-1:( infoLength_rcv + 1 )
           data_rcv( i ) = []; 
        end
% Если фактическая меньше - критическая ошибка. В программной модели она
% может наступить только в случае не правильного приема служебного поля,
% на практике, только в случае неисправности в радиоинтерфейсе т.к.
% в других случае, если ожидаемая длинна на приемнике окажется больше чем
% переданная отправителем, приемник будет принимать шумы радиоканала
    elseif infoLength_rcv > dataLength_rcv
        errorFlag = 1;
    end
    
%% Отображение интерполированной АЧХ КС
    if img == 1
        figure( 2 );
        plot( equInterpol ./ ampPilot, 'r' );
        grid on
        title( 'Интерполированная АЧХ канала связи (в номерах поднесущих)' )
    
%% Отображение СКС
        figure( 3 );
        plot( IQ_signal_rcv, 'x' );
        grid on
        title( 'Сигнально-кодовое созвездие принятого сигнала' )
    end;
    
%% Канальное декодирование
    L2_msgs_rcv = [];   
% Если во время приема физический уровень обнаружил критическую ошибку
% которая не позволит ему произвести декодирование, он выдает на КУ
% пустой пакет трафика L2 и соответствующий поднятый флаг errorFlag
    if errorFlag == 0
        for pack = 1:msgCount_rcv
% Выделение кодированного и перемеженного пакета L2
            packStart = ( pack - 1 ) * packLength_rcv + 1;
            L2_msg_cai_rcv = data_rcv( packStart:( packStart +  packLength_rcv - 1) );
% Деперемежение
            L2_msg_c_rcv = randdeintrlv( L2_msg_cai_rcv, 534 );
% Декодирование по Витерби
            L2_msg_rcv = vitdec( L2_msg_c_rcv, trell, 7, 'cont', 'hard' );
            L2_msgs_rcv = [ L2_msgs_rcv L2_msg_rcv ];
        end
    else
        L2_msgs_rcv = zeros( 1, 400 ); % "мусор"
        msgType_rcv = 0;
        msgCount_rcv = 1; 
    end

end

Графики,  полученные в ходе выполнения программы представлены на рисунках 6-8.


Рисунок 6- Временная реализация сообщения физического уровня для QPSK


Рисунок 7- Временная реализация сообщения физического уровня для QAM-16


Рисунок 8- Интерполированная АЧХ КС


2.3 Исследование процедуры тактовой (символьной) синхронизации физического уровня.

 

 В ходе моделирования прохождения сигнала по каналу связи приемная часть не знает точного времени прихода OFDM-сигнала. Процесс синхронизации в коде модели представляет собой процесс обнаружения OFDM-сигнала с помощью скользящего по сигналу окна размером 320 отсчетов (как и преамбула) и последующего определения минимума СКО между окном и преамбулой

        Сначала составляется массив всех окон принятого сигнала длинной 320 отсчетов (длинна преамбулы). Для каждого элемента этого массива находится СКО двух блоков: окна и преамбулы. Потом из полученной выборки находится наименьшее значение СКО рисунок 9, свидетельствующее о полном приеме преамбулы в окне с началом в точке минимума - следовательно, отложив от этой точки 320 отсчетов можно найти начало служебного, а значит и информационного поля сообщения.

Листинг №2

%% Синхронизация
% Подготовка окна    
    sync_rcv = zeros(1, length( l1Frame_rcv ) - length( Preamb_Full ) );
% Сдвиг и расчет СКО
    for i = 1: ( length( l1Frame_rcv ) - length( Preamb_Full ) )
       searchBlock = l1Frame_rcv( i: ( i - 1 + length( Preamb_Full ) ) );
       sync_rcv(i) = sum( abs( searchBlock - Preamb_Full).^2 );
    end
% Нахождение минимума СКО и соответственно, начала преамбулы  
    [ SKO_min Preamb_Start_rcv ] = min( sync_rcv );
% Определение окончания преамбулы   
    Preamb_End_rcv = Preamb_Start_rcv + length( Preamb_Full );

% Отображение графика    
    if img == 1
        figure( 4 );
        plot( sync_rcv );
        grid on
        title( 'СКО между двумя блоками: скользящим окном и преамбулой' )
    end


Рисунок 9- минимумы СКО


2.4. Исследование качества приема сообщений по различным каналам связи.

Для исследования прохождения сообщения по каналу связи в программном модуле присутствует возможность включения моделирования AWGN-канала.  

    Пронаблюдаем прохождения сообщения по каналу связи для различных условий в канале. При ОСШ = 20 дБ рисунок10 и рисунок11 сообщения приняты правильно при обоих профилях передачи.  


Рисунок 10- СКС принятого сигнала при ОСШ = 20 дБ и модуляции QPSK


Рисунок 11- СКС принятого сигнала при ОСШ = 20 дБ и модуляции QAM-16

 Постепенно снижая ОСШ найдем для каждого профиля модуляции такое значение ОСШ, при котором начинают появляться ошибки. В результате получаем 5 дБ для QPSK рисунок12 и 12 дБ для QAM-16 рисунок13.


Рисунок12 - СКС принятого сигнала при ОСШ = 5 дБ и модуляции QPSK


Рисунок 13- СКС принятого сигнала при ОСШ = 12 дБ и модуляции QAM-16

В процессе уменьшения ОСШ было получено критическое значение равное 3дБ, при котором сообщение  с наиболее помехоустойчивой модуляцией            ( QPSK) не удалось передать.

Сравнение теоретических ОСШ, полученных в пункте 1.6.7  , с практическими представлено в таблице1

  Таблица1 - Сравнение ОСШ для различных профилей


Выводы:

Моделирование передачи пакета трафика канального уровня показало, что система может передавать сообщения даже при малых значениях ОСШ , сопоставимых с теоретически полученными в пункте 1.4.7. (таблица1). Но также следует учесть, что в модели передавался всего один пакет L2, что не позволяло произвести достаточно точную оценку BER.  

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

1. 1.  Бакке А.В. «Лекции по курсу ССПО»

2. 2.  http://omoled.ru/publications/view/987

3. 3. http://omoled.ru/publications/view/973

4. 4. http://omoled.ru/publications/view/853

5. 5. http://citforum.ru/nets/tpns/glava_4.shtml.