Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Цель работы: получить практические навыки в использовании средств межпроцессного взаимодействия в ОС UNIX на примере моделирования цифровой системы управления.



Цель работы: получить практические навыки в использовании средств межпроцессного взаимодействия в ОС UNIX на примере моделирования цифровой системы управления.

 

Часть 1.

 

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

Y` = A*Y + B*v (1)

 

Yout = C*Y (2)

 

где Y - вектор переменных состояния объекта;

Y` - вектор первых производных переменных состояния объекта;

v - входная величина;

Yout - выходная величина;

A, B и C - матрицы с постоянными коэффициентами;

 

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

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

переопределить текст функции modl, так, чтобы она содержала систему уравнений (1) для вашего варианта;

переопределить выражение для вычисления выходной величины в соответствии с уравнением (2) для вашего варианта;

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

В. Запустить переработанную программу на исполнение, построить график полученной кривой разгона объекта и включить его в отчет. Для построения графика можно использовать программу gnuplot.

Г. Проверить корректность модели объекта. Для этого получить таблицу кривой разгона объекта при помощи программы myMik - для Linux или myMik.exe - для Windows. Для этого создать текстовый файл, содержащий описание структурной схемы объекта и состоящий из 3 частей:

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

входное воздействие V N v

пропорциональное звено P N k

интегрирующее звено I N t y0

апериодическое звено A N t k y0

где V,P.I,A - буква, определяющая тип звена;

N - номер звена;



v - входное воздействие;

k - коэффициент усиления звена;

t - постоянная времени звена;

y0 - начальное условие;

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

Nвх <- Nвых k

где Nвх, Nвых - номера входного и выходного звеньев;

k - коэффициент усиления на входе, обычно 1.0 или -1.0, в соответствии со знаком сумматора, через который проходит связь.

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

Программа myMik получает данный текстовый файл в качестве параметра командной строки. В ходе работы программа создает несколько текстовых файлов с именами outN.dat, где N - номер звена. Т.е. на выходе мы получаем зависимость выходной величины от времени для каждого из звеньев структурной схемы. Одно из звеньев является выходным и содержит данные, являющиеся кривой разгона всего объекта. Если на выходе объекта имеется сумматор, то после него можно добавить пропорциональное звено с коэффициентом усиления 1.0. Выход этого звена будет выходом объекта.

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

 

 

Рассмотрим получение кривой разгона объекта, представленного структурной схемой №:

 

В качестве переменных состояния выберем значения на выходе апериодических звеньев.

Система дифференциальных уравнений будет иметь вид:

 

py1[0]=((V-py[1])*K1-py[0])/T1; // y1

py1[1]=(py[0]*K5*K4*K3*K2-py[1])/T2; // y2

py1[2]=(V*K6-py[2])/T6; // y3

py1[3]=(V*K8-py[3])/T8; // y4

 

а выходная величина будет равна:

 

Yout =(Y[0]+Y[2])*K7+Y[3];

 

Шаг по времени будет 60/100 = 0.6; принимаем dT=1.0.
Продолжительность процесса 3*250 = 750.0

 

 

Текст программы для получения кривой разгона данного объекта будет следующим:

 

#ifdef HAVE_CONFIG_H

#include <config.h>

#endif

 

#include <stdio.h>

#include <stdlib.h>

 

typedef void (*mdl)(float t, float* py, float* py1);

void init_rk(int N, float** py);

void done_rk(float** py);

void rkt4(float t, float dt, float* py, mdl model);

 

 

void modl(float t, float* py, float* py1);

 

float* Y;

int n=4; // порядок системы

float dT,T,Tm;

float V;

float Yout;

float K1=1.8, K2=1.0, K3=2.8, K4=0.4, K5=1.7; // коэффициенты усиления

float K6=0.7, K7=2.9, K8=0.8;

float T1=190.0, T2=60.0, T6=250.0, T8=90.0; //постоянные времени звеньев

FILE *fout;

 

int main(){

init_rk(n, &Y);

T=0.0;

dT=1.0; // шаг по времени

Tm=750; // продолжительность процесса

V=1.0; // входное воздействие

 

Y[0]=Y[1]=Y[2]=Y[3]=0.0;

fout = fopen("razgon_ira.dat", "w");

 

while(T<Tm){

 

Yout =(Y[0]+Y[2])*K7+Y[3]; // выходная величина

 

fprintf(stderr,"%5.1f %8.5f\n",T,Yout);

fprintf(fout,"%5.1f %8.5f\n",T,Yout);

rkt4(T,dT,Y, &modl);

T+=dT;

}

fclose(fout);

done_rk(&Y);

return 0;

}

 

void modl(float t, float* py, float* py1){

 

py1[0]=((V-py[1])*K1-py[0])/T1; // система дифференциальных уравнений

py1[1]=(py[0]*K5*K4*K3*K2-py[1])/T2;

py1[2]=(V*K6-py[2])/T6;

py1[3]=(V*K8-py[3])/T8;

}

 

static float* k[4], *py1, *pdy;

static int N_s;

 

void init_rk(int N, float** py){

int i;

for (i=0; i<4; i++)

k[i]=(float*)calloc(N, sizeof(float));

*py=(float*)calloc(N, sizeof(float));

py1=(float*)calloc(N, sizeof(float));

pdy=(float*)calloc(N, sizeof(float));

N_s=N;

}

void done_rk(float** py){

for (int i=0; i<4; i++) free(k[i]);

free(*py);

free(py1);

free(pdy);

}

 

void rkt4(float t, float dt, float* py, mdl model){

int i;

for (i=0; i<N_s; i++) pdy[i]=py[i];

model(t,pdy,py1);

for (i=0; i<N_s; i++) k[0][i]=dt*(py1[i]);

for (i=0; i<N_s; i++) pdy[i]=py[i]+k[0][i]/2.0;

model(t+dt/2.0,pdy,py1);

for (i=0; i<N_s; i++) k[1][i]=dt*(py1[i]);

for (i=0; i<N_s; i++) pdy[i]=py[i]+k[1][i]/2.0;

model(t+dt/2.0,pdy,py1);

for (i=0; i<N_s; i++) k[2][i]=dt*(py1[i]);

for (i=0; i<N_s; i++) pdy[i]=py[i]+k[2][i];

model(t+dt,pdy,py1);

for (i=0; i<N_s; i++) k[3][i]=dt*(py1[i]);

for (i=0; i<N_s; i++){

pdy[i]=(k[0][i]+2.0*k[1][i]+2.0*k[2][i]+k[3][i])/6.0;

py[i]+=pdy[i];

}

}

 

В результате работы программы был получен файл razgon_ira.dat, который был использован для построения графика кривой разгона объекта

 

 

 

Cоздаем текстовый файл obj_ira.dat, содержащий описание структурной схемы объекта. Для этого пронумеруем звенья структурной схемы, как показано на рисунке от 1 до 10. В результате получится:

 

 

V 1 1.0

A 2 190 1.8 0.0

A 3 60 1.0 0.0

P 4 2.8

P 5 0.4

P 6 1.7

A 7 250 0.7 0.0

P 8 2.9

A 9 90 0.8 0.0

P 10 1.0

&

2<-1 1.0

2<-3 -1.0

3<-4 1.0

4<-5 1.0

5<-6 1.0

6<-2 1.0

7<-1 1.0

8<-2 1.0

8<-7 1.0

9<-1 1.0

10<-8 1.0

10<-9 1.0

T

1.0

 

Выход объекта совпадает с выходом звена N10. Сравниваем между собой содержимое файлов razgon_ira.dat и out10.dat:

 

Как видим, имеется полное совпадение, следовательно, математическая модель объекта в виде системы дифференциальных уравнений соответствует структурной схеме.

 

Часть 2.

 

А. Переработать прилагаемые программы диспетчер, регулятор и объект таким образом, чтобы они соответствовали вашему варианту.
Программа-объект, также как и программа для получения кривой разгона должна включать в себя глобальные переменные, соответствующие коэффициентам усиления и постоянным времени звеньев структурной схемы, шаг по времени, текст функции modl, содержащий систему уравнений (1) для вашего варианта, выражение для вычисления выходной величины в соответствии с уравнением (2) для вашего варианта.
Программа регулятор должна при каждом вызове определять текущее значение ошибки, интеграл от ошибки (методом прямоугольников) и первую производную от ошибки (как отношение разностей), а также вычислять управляющее воздействие на объект на основе ПИД-закона регулирования.
Программа диспетчер должна определять общее время процесса - это максимальная постоянная времени объекта, умноженная на 6, а также соотношение шагов по времени регулятора и объекта; на первом этапе это величина равна 10. Диспетчер координирует работу регулятора и объекта при помощи группы из 2-х процессных семафоров.
В разделяемой памяти размещаются следующие переменные:

Yt - текущее значение величины на выходе объекта;

Yn - требуемой значение величины на выходе объекта (во всех вариантах это 1.0);

Ur - управляющее воздействие, вычисленное регулятором;

dt - шаг по времени объекта;

t - текущее время;

final - флажок, свидетельствующий об окончании процесса;

Nreg - соотношение шагов по времени регулятора и объекта;

 


Б. Запустить на исполнение программы в следующей последовательности: регулятор, объект, диспетчер.
Установить соотношение шагов по времени регулятора и объекта равным 10.
Подобрать параметры настройки ПИД-регулятора, так, чтобы переходный процесс имел более или менее приемлемые показатели качества регулирования.
Записать в два текстовых файла величину на выходе объекта и управляющее воздействие, а также время.
Построить графики по данным этих текстовых файлов и включить их в отчет.
В. Установить соотношение шагов по времени регулятора и объекта равным 100.
Построить графики по данным текстовых файлов (величина на выходе объекта и управляющее воздействие в функции времени) и включить их в отчет.

 

РЕГУЛЯТОР

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/shm.h>

#include <sys/sem.h>

 

#define MEM 0x1234 //ключ участка разделяемой памяти

#define SEM 0xABBA //ключ набора семафоров

 

union semun //объединение для работы с процессными семафорами

{

int val; //начальное значение счетчика

struct semid_ds *buf;

unsigned short *array;

struct seminfo *__buf;

};

 

union semun sm;

 

struct sembuf smb; //описываем переменную для процессного семафора

 

int dmem, dsem;

char* pmem;

float *Yt, *Yn, *Ur, *Uo, *dt, *t;

int *final;

int *Nreg;

 

float eps;

float K=0.8, Q=0.005, Td=0.0001; //коэффициенты ПИД-регулятора

float ieps;

float deps;

float peps;

 

int main(int argc, char *argv[])

{

dmem=shmget(MEM, getpagesize(), IPC_CREAT | S_IRUSR | S_IWUSR); //получаем идентификатор участка разделяемой памяти

pmem=(char*)shmat(dmem,0,0); //подключаемся к разделяемой памяти

dsem=semget(SEM, 2, IPC_CREAT | S_IRUSR | S_IWUSR); //подключаемся к набору семафоров

sm.val=0; //устанавливаем начальное значение счетчика

semctl(dsem,1,SETVAL,sm); //инициализируем семафор

 

smb.sem_num=1; //работаем с первым семафором из набора

smb.sem_flg=0;

smb.sem_op=-1; //устанавливаем операцию над счетчиком семафора

 

Yt=(float*)pmem; //инициализируем переменные

Yn=(float*)(pmem+1*sizeof(float));//в разделяемой памяти

Ur=(float*)(pmem+2*sizeof(float));

dt=(float*)(pmem+4*sizeof(float));

t=(float*)(pmem+5*sizeof(float));

final=(int*)(pmem+6*sizeof(float));

Nreg=(int*)(pmem+6*sizeof(float)+sizeof(int));

 

*final=0; //устанавливаем флаг конца обмена в ноль

*Yn = 1.0; //величина задания

*Ur=0.0;

ieps=0.0;

peps=0.0;

 

//входим в цикл обмена, условие выхода - установка флага конца обмена в 1

while(!*final){

semop(dsem, &smb, 1); //уменьшаем счетчик семафора первый раз

eps= *Yn - *Yt; //вычисляем ошибку регулирования

ieps+=eps*(*dt)*(*Nreg);

deps = (peps-eps)/(*dt)/(*Nreg);

peps = eps;

*Ur = K*eps + Q*ieps + Td*deps; //вычисляем управляющее воздействие

semop(dsem, &smb, 1); //уменьшаем счетчик семафора второй раз

}

return 0;

}

 

 

ОБЪЕКТ

 

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/shm.h>

#include <sys/sem.h>

 

#define MEM 0x1234 //ключ участка разделяемой памяти

#define SEM 0xABBA //ключ набора семафоров

 

typedef void (*mdl)(float t, float* py, float* py1);

void init_rk(int N, float* *py);

void done_rk(float** py);

void rkt4(float t, float dt, float* py, mdl model);

void modl(float t, float* py, float* py1);

 

union semun //объединение для работы с процессными семафорами

{

int val; //начальное значение счетчика

struct semid_ds *buf;

unsigned short *array;

struct seminfo *__buf;

};

 

union semun sm;

struct sembuf smb; //описываем переменную для процессного семафора

 

int dmem, dsem;

char* pmem;

 

float* Y;

int n=4;

float V;

float K1=1.8, K2=1.0, K3=2.8, K4=0.4, K5=1.7; //коэффициенты звеньев ОУ

float K6=0.7, K7=2.9, K8=0.8; //коэффициенты звеньев ОУ

float T1=190.0, T2=60.0, T6=250.0, T8=90.0; //постоянные времени звеньев ОУ

int *final;

float *Yt, *Yn, *Ur, *dt, *t;

FILE *fYout, *fYin; //дескрипторы файлов с данными

int main(){

dmem=shmget(MEM, getpagesize(), IPC_CREAT | S_IRUSR | S_IWUSR); //получаем идентификатор участка разделяемой памяти

pmem=(char*)shmat(dmem,0,0); //подключаемся к разделяемой памяти

dsem=semget(SEM, 2, IPC_CREAT | S_IRUSR | S_IWUSR); //подключаемся к набору семафоров

sm.val=0; //устанавливаем начальное значение счетчика

semctl(dsem,0,SETVAL,sm); //инициализируем семафор

 

smb.sem_num=0; //работаем с нулевым семафором из набора

smb.sem_flg=0;

smb.sem_op=-1; //устанавливаем операцию над счетчиком семафора

 

Yt=(float*)pmem; //инициализируем переменные

Yn=(float*)(pmem+1*sizeof(float));//в разделяемой памяти

Ur=(float*)(pmem+2*sizeof(float));

dt=(float*)(pmem+4*sizeof(float));

t=(float*)(pmem+5*sizeof(float));

final=(int*)(pmem+6*sizeof(float));

init_rk(n, &Y); //выделяем память под переменные

Y[0]=Y[1]=Y[2]=Y[3]=0.0; //начальные значения переменных на выходе системы

*final=0; //устанавливаем флаг конца обмена в ноль

*t=0.0; //начало отсчета по времени

*dt=1.0; //шаг по времени

fYout=fopen("Yout.dat","w"); //открываем файл Yout на запись

fYin=fopen("Yin.dat","w"); //открываем файл Yin на запись

 

//входим в цикл обмена, условие выхода - установка флага конца обмена в 1

while(!*final){

semop(dsem, &smb, 1); //уменьшаем счетчик семафора первый раз

*Yt = (Y[0]+Y[2])*K7+Y[3]; //вычисляем выходную величину

 

 

fprintf(fYout,"%7.2f %9.5f\n", *t, *Yt); //записываем в файл Yout выходную величину

fprintf(fYin,"%7.2f %12.5g\n", *t, *Ur); //записываем в файл Yin управляющее воздействие

fprintf(stderr,"%7.2f %9.5f\n", *t, *Yt); //выводим на экран выходную величину

 

rkt4(*t,*dt,Y, &modl); //решаем систему диф. уравнений

*t+=*dt; //увеличиваем время

semop(dsem, &smb, 1); //уменьшаем счетчик семафора второй раз

}

fclose(fYout); //закрываем файлы

fclose(fYin);

return 0;

}

 

void modl(float t, float* py, float* py1){ //функция моделирует поведение

V = *Ur; //объекта управления

//через систему диф. уравнений

py1[0]=((V-py[1])*K1-py[0])/T1;

py1[1]=(py[0]*K5*K4*K3*K2-py[1])/T2;

py1[2]=(V*K6-py[2])/T6;

py1[3]=(V*K8-py[3])/T8;

}

 

static float* k[4], *py1, *pdy;

static int N_s;

 

void init_rk(int N, float** py){ //функция производит выделение

int i; //динамической памяти

for (i=0; i<4; i++) k[i]=(float*)calloc(N, sizeof(float));

*py=(float*)calloc(N, sizeof(float));

py1=(float*)calloc(N, sizeof(float));

pdy=(float*)calloc(N, sizeof(float));

N_s=N;

}

 

void done_rk(float** py){ //функция освобождает динамическую память

for (int i=0; i<4; i++) free(k[i]);

free(*py);

free(py1);

free(pdy);

}

 

void rkt4(float t, float dt, float* py, mdl model){ //функция моделирует

int i; //решение системы

for (i=0; i<N_s; i++) pdy[i]=py[i]; //диф. уравнений

model(t,pdy,py1); //методом Рунге-Кутта

for (i=0; i<N_s; i++) k[0][i]=dt*(py1[i]);

for (i=0; i<N_s; i++) pdy[i]=py[i]+k[0][i]/2.0;

model(t+dt/2.0,pdy,py1);

for (i=0; i<N_s; i++) k[1][i]=dt*(py1[i]);

for (i=0; i<N_s; i++) pdy[i]=py[i]+k[1][i]/2.0;

model(t+dt/2.0,pdy,py1);

for (i=0; i<N_s; i++) k[2][i]=dt*(py1[i]);

for (i=0; i<N_s; i++) pdy[i]=py[i]+k[2][i];

model(t+dt,pdy,py1);

for (i=0; i<N_s; i++) k[3][i]=dt*(py1[i]);

for (i=0; i<N_s; i++){

pdy[i]=(k[0][i]+2.0*k[1][i]+2.0*k[2][i]+k[3][i])/6.0;

py[i]+=pdy[i];

}

}

 

ДИСПЕТЧЕР

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/shm.h>

#include <sys/sem.h>

 

#define MEM 0x1234 //ключ участка разделяемой памяти

#define SEM 0xABBA //ключ набора семафоров

 

union semun //объединение для работы с процессными семафорами

{

int val;

struct semid_ds *buf;

unsigned short *array;

struct seminfo *__buf;

};

 

union semun sm;

 

struct sembuf smb_r, smb_o; //описываем семафоры для взаимодействия с

//регулятором и ОУ

 

int dmem, dsem;

char* pmem;

 

float *Yt, *Yn, *Ur, *Uo, *dt, *t;

int *final;

int *Nreg;

float Tm;

 

int main()

{

dmem=shmget(MEM, getpagesize(), IPC_CREAT | S_IRUSR | S_IWUSR); //получаем идентификатор участка разделяемой памяти

 

pmem=(char*)shmat(dmem,0,0); //подключаемся к разделяемой памяти

 

dsem=semget(SEM, 2, IPC_CREAT | S_IRUSR | S_IWUSR); //подключаемся к набору семафоров

 

smb_o.sem_num=0; //семафор для взаимодействия с ОУ

smb_o.sem_flg=0;

 

smb_r.sem_num=1; //семафор для взаимодействия с ПИД-регулятором

smb_r.sem_flg=0;

 

Yt=(float*)pmem; //инициализируем переменные

Yn=(float*)(pmem+1*sizeof(float)); //в разделяемой памяти

Ur=(float*)(pmem+2*sizeof(float));

dt=(float*)(pmem+4*sizeof(float));

t=(float*)(pmem+5*sizeof(float));

final=(int*)(pmem+6*sizeof(float));

Nreg=(int*)(pmem+6*sizeof(float)+sizeof(int));

*Yn = 1.0; //величина задания

Tm = 1500.0; //продолжительность обмена

*Nreg = 10; //отношение шага объекта к шагу регулятора

 

//входим в цикл обмена, условие выхода - истечение времени, отведенного на процесс регулирования

while(*t < Tm)

{

smb_r.sem_op=2; //операция над счетчиком: +2

semop(dsem, &smb_r,1); //выполняем операцию

smb_r.sem_op=0; //операция над счетчиком: +0

semop(dsem, &smb_r,1); //попытка выполнить операцию

 

smb_o.sem_op=(*Nreg)*2; //операция над счетчиком: +2*Nreg

semop(dsem, &smb_o,1); //выполняем операцию

smb_o.sem_op=0; //операция над счетчиком: +0

semop(dsem, &smb_o,1); //попытка выполнить операцию

}

*final=1; //устанавливаем флаг конца обмена в единицу

shmdt(pmem); //отключаемся от разделяемой памяти

shmctl(dmem,IPC_RMID,0); //удаляем участок разделяемой памяти

semctl(dsem,0,IPC_RMID,sm); //удаляем набор семафоров

return 0;

}

 

 

Nreg = 10

 

 

 

Nreg = 100

 


Дата добавления: 2015-11-04; просмотров: 24 | Нарушение авторских прав




<== предыдущая лекция | следующая лекция ==>
Министерство образования и науки Российской Федерации | Тема работы: Сглаживание эмпирических данных и численное дифференцирование.

mybiblioteka.su - 2015-2024 год. (0.071 сек.)