ПЗ (1204320), страница 5
Текст из файла (страница 5)
Visual Studio включает в себя редактор исходного кода с поддержкой технологии IntelliSense и возможностью простейшего рефакторинга кода, встроенный отладчик, редактор форм для упрощения создания графического интерфейса приложения, веб-редактор, дизайнер классов и дизайнер схемы базы данных.
Visual Studio позволяет создавать и подключать сторонние дополнения (плагины) для расширения функциональности практически на каждом уровне, включая добавление поддержки систем контроля версий исходного кода (как, например, Subversion и Visual SourceSafe), добавление новых наборов инструментов (например, для редактирования и визуального проектирования кода на предметно-ориентированных языках программирования) или инструментов для прочих аспектов процесса разработки программного обеспечения (например, клиент Team Explorer для работы с Team Foundation Server) [27].
Недостатком данной среды является то что она проприетарна (платная).
Вывод
Qt подходит для разработки программного комплекса так как обладает возможностью создавать GUI, бесплатен, обладает хорошей документацией к собственным классам, и слотов\сигналов.
-
Разработка программы
Разработка комплекса будет вестись в несколько этапов:
– выделение модулей с отдельные классы и разработка структур данных;
– разработка интерфейса основных модулей;
– написание модуля сбора;
– написание модуля просмотра данных;
– написание модуля анализа данных;
– написание модуля создания отчётов;
– окончательная сборка и компоновка комплекса.
-
Выделение классов
В ходе анализа интерфейсов и структур различных программ было решено сделать основным окном (класс MainWindow) модуль просмотра данных. Это позволит сконцентрировать сделать функционал просмотра базовым и не концентрировать на нём лишнего внимания.
Класс сбора данных (GatherWindow) было решено сделать наименее зависимым от остальных, чтобы в дальнейшем этот модуль можно было выделить как отдельную подпрограмму для необходимости.
Анализирующий модуль и модуль отчётов решено выделить в отдельный класс (AnalizWindow) так как вся информация о весоизмерениях появляется после анализа собранных данных.
-
Основная структура данных
Для хранения основных данных в программе было решено создать структуру AllData. В данной структуре находятся стандартные настройки АЦП ЛА-20USB и хранятся обработанные и необработанные данные.
struct AllData{
QVector<short> fresh_data[2];
QVector<double> fresh_points_x[2];
QVector<double> fresh_points_y[2];
QVector<short> sm_data[2];
QVector<QPoint> max1_points[2];
QVector<QPoint> max2_points[2];
QVector<QPoint> min_points[2];
QVector<short> weight_data[2];
int minimum[2];
int maximum[2];
QString saveFileName;
unsigned short ByteWeight;
unsigned short InternalBufferSize = 4096;
unsigned short ChanallNumber = 2;
double freq = 25000.0;
};
В дальнейшем планируется реализовать передачу данных из модуля в модуль без постоянного открытия данных. Однако на данном этапе разработки это не повлияет на производительность.
-
Разработка интерфейса
Основное окно программы (рисунок 13) будет содержать виджет для вывода графиков с возможностью переключения отображения графика, кнопка открытия данных для просмотра загружающая данные из файла в структуру, кнопки модуля сбора и модуля анализа. Горизонтальный ползунок позволяет перемещать график влево/вправо для навигации по нему, вертикальный ползунок уменьшает/увеличивает количество одновременно отображаемых точек для более тщательного/общего просмотра графиков.
Рисунок 13 – Интерфейс MainWindow
Интерфейс AnalizWindow показан на рисунке 14, и делится на две части. Первая часть содержит кнопку «Открыть файл» загружающая данные сбора, информационные строки в которых отображается предварительная информация, проанализированная на основе «свежих» данных, кнопка «Анализ данных» запускающая анализ и область «Данные о поезде» в которой отображаются данные после анализа.
Рисунок 14 – Интерфейс AnalizWindow
Вторая часть содержит таблицу, в которую выводится проанализированная информация. Данные из этой таблицы можно сохранить при помощи кнопки «Экспортировать в файл таблицы».
Интерфейс модуля сбора (рисунок 15) имеет выпадающее меню с выбором одного из установленных в системе устройств АЦП. Кнопка «Подключить» инициализирует устройство и пытается присоединиться к нему. Если подключение прошло с ошибкой пользователь уведомляется об ошибке. Кнопка «Старт/Стоп» запускает/останавливает сбор данных. Кнопка «Сохранить» позволяет произвести запись в файл собранных данных, а при отметке чекбокса «Сохранить информацию о сборе» дополнительно будет записан текстовый файл с информацией о сборе и данными в текстовом варианте.
Рисунок 15 –Интерфейс GatherWindow
Кнопкой «Изменить настройки» открывается окно настроек (рисунок 16) которое позволяет настроить параметры АЦП.
Рисунок 16 – Окно настроек АЦП
Для настройки АЦП доступны:
– частота дискретизации: количество собранных данных в секунду;
– количество каналов: число датчиков, подключенных к АЦП для произведения сбора, должно быть кратно двум (от 2 до 8);
– коэффициент усиления: коэффициент, отвечающий за усиление сигнала в целях использования всего диапазона точности сбора (от 1 до 32);
– размер буфера: количество килобайт данных собранных АЦП до получения сигнала прерывания.
При использовании кнопки «Сбросить» производится откат изменений настроек, кнопка «Выход» подтверждает и применяет новые настройки.
-
Создание модуля сбора данных
Цель данного модуля связь с АЦП и сбор данных с него. В комплекте поставки с АЦП идёт пакет драйверов, который будет основной частью модуля [24].
Так как сбор данных подразумевает постоянный цикл, который должен опрашивать устройство ожидая сигнал прерывания для данной цели потребуется отдельный поток. Если этого не сделать интерфейс программы будет находиться в зависшем состоянии и отключить сбор будет невозможно.
Структура класса потока выглядит следующим образом:
class WorkerThread : public QThread
{
Q_OBJECT
public:
void run() Q_DECL_OVERRIDE;
void testRun();
public slots:
void changeState(bool st);
void setData(QVector<ushort> a);
QVector<ushort> getData();
bool connect(U32 deviceId, QString boardName);
bool saveToFile(QString str, bool saveTxt);
signals:
void errorEmit(QString s);
void gatherBlock(QString,int);
private:
IRshDevice* device;
RshDllClient Client;
QVector<RSH_BUFFER_S16> arrayBuffer;
RSH_BUFFER_U8 userBuffer1;
bool state;
U32 BufferSize;
U32 ChannelNumber;
U32 GainKoef;
double SampleFreq;
};
Основной метод run() перегружен и описан в программе как метод непрерывного сбора, метод testRun() используется для однократного сбора данных с АЦП для проверки поджатия.
Слот changeState() является переключателем бесконечного цикла сбора и управляет приватной переменной bool state. Слоты setData() и getData() необходимы для передачи данных настроек АЦП в поток и обратно.
Слот Connect() инициализирует структуру IRshDevice device используя RhsDllClient Client который позволяет собрать данные о установленных в системе устройствах АЦП.
Для произведения подключения к устройству производится инициализация структуры RshDllInterfaceKey которая создает интерфейс к драйверу устройства по названию устройства и его идентификационному номеру (ID). Методом RshDllClient::GetDeviceInterface(RshDllInterfaceKey) получаем интерфейс устройства. Далее методом IRshDevice::Connect() подключаемся к устройству по ID.
Слот saveToFile() связан с кнопкой «Сохранить» и производит сохранение RSH_BUFFER_U8 userBuffer1 при помощи метода WriteBufferToFile(std::string).
Сигнал errorEmit(QString) выводит сообщение об ошибке в виде всплывающего QMessageBox. Сигнал gatherBlock(QString,int) выводит информацию о ходе сбора из потока в statusLabel или textBrowser в зависимости от второго аргумента функции.
Основной класс GatherDialog имеет следующую структуру:
class GatherDialog : public QDialog
{
Q_OBJECT
WorkerThread *potok;
public:
explicit GatherDialog(QWidget *parent = 0);
~GatherDialog();
public slots:
void getError(QString str);
void gathered(QString a, int pos);
private slots:
void on_connectButton_clicked();
void on_startStopButton_clicked(bool checked);
void on_saveButton_clicked();
void on_testButton_clicked();
void on_settingButton_clicked();
private:
Ui::GatherDialog *ui;
QString saveFilename;
RshDllClient Client;
};
Класс имеет стандартный конструктор и деструктор, слоты кнопок, принимающие из потока слоты getError(QString) и gathered(QString, int). Переменная QString saveFilename хранит информацию о имени сохранёного файла.
RshDllClient Client используется для получения информации об установленных в системе драйверах устройств и заполнении выпадающего списка.
-
Создание модуля отображения данных
Модуль отображения является основным телом программы QMainWindow и имеет выпадающие меню с функциональной (пункт «Меню») и информационной (пункт «О программе») частями. Кнопки «Открыть файл», «Сбор данных» и «Анализ» вынесены на основной экран для быстрого доступа. Виджет вывода графиков построен на основе библиотеки QCustomPlot.
Открытие файла происходит отдельным потоком из-за массивности собранных данных. Код тела потока приведён ниже.
void FeelThread::run(){
short buff,rbuff;
QFile F(filename);
if(!filename.isEmpty()){
F.open(QIODevice::ReadOnly);
int i=0;
if(F.isOpen()){
qDebug() << "ifopen" << filename;
if(!datas->fresh_data[0].isEmpty()){
qDebug() << "ifEmptyData";
datas->fresh_data[0].clear();
datas->fresh_data[1].clear();
}
for(;;i++){
if(!F.atEnd()){
F.read(reinterpret_cast<char *>(&buff), 2);
rbuff = ((buff&0xFFF0)>>4);
if(rbuff>4094) datas->fresh_data[i%2].append(0);
else datas->fresh_data[i%2].append(rbuff);
}
else break;
if(i%1000==0) emit gatherFeed(QString("Собрано " + QVariant(i).toString() + " куска данных"));
}
emit gatherFeed(QString("Собрано " + QVariant(i).toString() + " куска данных"));
F.close();
}
else qDebug() << "cant open " << filename;
emit plotGraphs();
emit gatherFeed(QString("Обработано " + QVariant(i).toString() + " куска данных"));
}
qDebug() << "Thread Ended";
}
Открытие файла производится в режиме «только для чтения» так как необходимо не допустить изменения и порчи данных. После запускается цикл с проверкой конца файла (EOF). Методом read читаем два байта информации, приводим их к нормальному виду сдвигая на 4 бита влево для получения реальных данных. Далее производится проверка данных на наличие отрицательных значений в буфере и запись значения в массив. Каждую тысячную итерацию срабатывает сигнал gatherFeed(QString) отправляющий информацию о ходе обработки данных который связан с слотом showMessage(QString) строки состояния интерфейса.
В заключение производится закрытие файла и срабатывает сигнал plotGraphs() запускающий построение графиков в QCustomPlot виджете.
Для того чтобы вывести график на экран необходимо уменьшить количество точек для вывода. Для этого был написан следующий блок кода:
for(int a=0; a<2; a++){
datas->fresh_points_x[a].clear();
datas->fresh_points_y[a].clear();
datas->minimum[a]=0;
datas->maximum[a]=0;
double pointo = datas->fresh_data[a][0];
datas->fresh_points_x[a] << 0;
datas->fresh_points_y[a] << pointo;
for(double i=1; i<datas->fresh_data[a].size(); i++){
if(pointo != datas->fresh_data[a][i]){
datas->fresh_points_x[a] << i-1;
datas->fresh_points_y[a] << pointo;
datas->fresh_points_x[a] << i;
datas->fresh_points_y[a] << (double)datas->fresh_data[a][i];
if(datas->maximum[a]<datas->fresh_data[a][i])
datas->maximum[a]=datas->fresh_data[a][i];
pointo = datas->fresh_data[a][i];
}
}
datas->fresh_points_x[a] << (double)datas->fresh_data[a].size()-1;
datas->fresh_points_y[a] << pointo;















