Статьи

Создание веб-приложения с MATLAB и средним стеком

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

  • MATLAB понимает данные формата матрицы, в то время как веб-приложения предпочитают данные в формате JSON или XML.
  • Часто данные создаются и используются внутри программы MATLAB, что ограничивает свободу, которую разработчики любят иметь в отношении сохранения данных, их использования и т. Д.

Было бы намного проще создавать приложения, если бы MATLAB предоставлял данные в JSON, а веб-приложение могло использовать эти данные JSON из MATLAB для создания чего-то замечательного.

В этой статье мы разработаем небольшую демонстрацию, чтобы продемонстрировать, как совместить MATLAB и MEAN-стек.

О веб-приложении

Веб-приложение будет включать передачу данных из MATLAB в браузер в режиме реального времени. Для простоты мы переведем текущее время из MATLAB и отобразим его в браузере. Мы будем использовать JSONlab , набор инструментов для кодирования / декодирования файлов JSON в MATLAB. Веб-приложение будет создано с использованием стека MEAN. Если вы не знакомы со стеком MEAN, я предлагаю вам прочитать статью Введение в стек MEAN, прежде чем двигаться дальше.

Введение в JSONlab

JSONlab — это бесплатная реализация кодера / декодера JSON для языка MATLAB с открытым исходным кодом. Его можно использовать для преобразования структуры данных MATLAB (массива, структуры, ячейки, массива структуры и массива ячеек) в форматированную строку JSON или декодирования файла JSON в данные MATLAB.

Это дает нам доступ к четырем функциям: loadjson() , savejson() , loadubjson() и saveubjson() . Последние две функции используются для обработки формата UBJSON . loadjson() используется для преобразования строки JSON в связанный объект MATLAB. В нашем проекте мы будем использовать только savejson() которая преобразует объект MATLAB (ячейка, структура или массив) в строку JSON. Его можно использовать следующими способами:

 json = savejson(rootname, obj, filename) json = savejson(rootname, obj, opt) json = savejson(rootname, obj, 'param1', value1, 'param2', value2, ...) 

Поскольку мы должны написать файл, мы будем использовать первую подпись. Он возвращает строку JSON, а также записывает строку в файл.

Установка JSONlab

Для начала загрузите JSONlab , разархивируйте архив и добавьте путь к папке в список путей MATLAB с помощью следующей команды:

 addpath('/path/to/jsonlab'); 

Если вы хотите добавить этот путь навсегда, вам нужно ввести pathtool , перейти в корневую папку JSONlab и добавить его в список. После этого вы должны нажать «Сохранить». Затем запустите rehash в MATLAB и наберите which loadjson . Если вы видите вывод, это означает, что JSONlab установлен правильно.

Код MATLAB

Нам нужно текущее время, поэтому мы будем использовать команду clock . Возвращает вектор даты из шести элементов, содержащий текущую дату и время в формате [year month day hour minute seconds] . Чтобы получить время повторно, мы поместили команду clock в бесконечный цикл while. Таким образом, мы получаем данные в реальном времени, пока выполнение скрипта не будет прекращено, используя Ctrl+C в командном окне MATLAB.

Следующий код реализует эту идею:

 format shortg; y=0; while y = 0 % c = [year month day hour minute seconds] c=clock; % Rounding every value to an integer c=fix(c); x.clock=c; % accessing the 4th column of c, ie hours x.hours=c(:,4); % accessing the 5th column of c ,ie minutes x.minutes=c(:,5); % accessing the 6th column of c, ie seconds x.seconds=c(:,6); % converting x into JSON and writing as matlabData.json savejson('',x,'data/matlabData.json'); end 

В нашем проекте нас интересуют часы, минуты и секунды. Функция fix(c) , используемая в приведенном выше коде, округляет все элементы матрицы до ближайшего целого числа. Для получения hour данных нам нужно значение 4- го столбца матрицы, поэтому мы используем команду c(:,4) . Используя тот же подход, мы получаем минуты и секунды.

Мы отправим clock и некоторые из его отдельных переменных отдельно в веб-приложение, чтобы показать преобразование различных типов данных из объекта MATLAB в JSON. Хотя данные clock будут преобразованы в Array , значения часов, минут и секунд будут преобразованы в Number как мы увидим позже.

В нашем проекте мы будем использовать savejson() для преобразования и записи переменной x в формате JSON в файле matlabData.json . Параметр rootname будет пустой строкой для простоты.

С помощью предыдущего кода весь код MATLAB, который нам нужен, готов. Теперь, как только мы запустим скрипт, мы можем заметить, что файл JSON создается внутри папки data и данные в файле автоматически продолжают обновляться. Пример содержимого файла JSON показан ниже:

 { "hours": 19, "minutes": 28, "seconds": 28, "clock": [2015,5,27,19,28,28] } 

Мы будем смотреть этот файл и читать последние данные, используя Node.js. Давайте теперь начнем создавать веб-приложение.

Веб-приложение

Теперь, когда наши данные из MATLAB были преобразованы в JSON и хранятся в файле, мы можем независимо прочитать этот файл и получить данные, наблюдая за изменениями. Эта операция полностью независима от MATLAB. В оставшейся части статьи я предполагаю, что вы обладаете некоторыми знаниями о socket.io и стеке MEAN, хотя мы будем использовать только их основные понятия.

Давайте начнем писать веб-приложение.

Создание файла Package.json

Чтобы начать с нашего приложения, давайте определим зависимости нашего проекта. Для этого мы создадим файл package.json, который выглядит следующим образом:

 { "name": "matlab-mean-demo", "version": "1.0.0", "description": "A demo web-app using Matlab and MEAN stack", "main": "server.js", "dependencies": { "express": "latest", "mongoose": "latest", "socket.io": "^1.2.0" } 

После создания файла запустите npm install в корневой папке проекта, чтобы все зависимости были установлены. Если вы не знакомы с npm , я предлагаю вам прочитать Руководство для начинающих по npm — Node Package Manager .

Серверный код

Эта часть кода включает в себя использование Node.js, Express и MongoDB. Действия, выполняемые сервером:

  • Обслуживание файла index.html
  • Просмотр и чтение данных из файла JSON
  • Сохранение данных в базе данных с использованием MongoDB
  • Отправка данных в браузер с помощью socket.io

Мы создадим файл с именем server.js в корневой папке, где мы напишем код, необходимый для всех описанных функций.

Мы обслуживаем статические файлы, используя Express:

 // Defining the root directory for static files app.use(express.static(__dirname + '/app')); // Serving the static HTML app.get("/", function(req, res) { res.sendfile("/index.html"); }); 

Когда запрос отправляется в / , файл index.html хранящийся в каталоге app будет обслуживаться.

Чтобы просмотреть файл на предмет каких-либо изменений, мы используем fs.watch() а для чтения файла при каждом изменении — fs.readFile() . Как только изменение обнаружено, файл читается, и мы получаем данные. Весь процесс выполняется с помощью следующего кода:

 fs.watch('folderName',function(event,filename){ fs.readFile('folderName' + filename, function(err,data){ console.log(data); }); }); 

Когда соединение с клиентом установлено и мы начинаем получать данные, мы выполняем две операции:

  1. Отправьте данные в браузер с помощью функции emit emit() файла socket.io.
  2. Сохраните данные в MongoDB, используя промежуточное ПО mongoose

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

 // Creation of the schema var dataSchema = mongoose.Schema({ clock: Array, hours: Number, minutes: Number, seconds: Number }); // Creating a model based on schema var appData = mongoose.model('appData', dataSchema); 

В последнем утверждении предыдущего фрагмента мы создаем модель на основе определенной схемы. Первым аргументом, переданным функции, является единственное имя коллекции, для которой предназначена наша модель. Mongoose автоматически назначает имя множественного числа для коллекции. Итак, appData — это модель коллекции appDatas .

Когда мы получаем новые данные, мы создаем новый экземпляр этой схемы с последними данными и сохраняем его в базе данных с помощью метода save() . Этот экземпляр известен как документ . В приведенном ниже коде savingData является документом.

Окончательный код этой части показан ниже:

 var express = require('express'); var mongoose = require('mongoose'); var fs = require('fs'); var app = express(); //Make a connection to MongoDB mongoose.connect('MongoDB://localhost/matlabMeanDemo'); var io = require('socket.io')(app.listen(3000)); //Defining the root directory for static files app.use(express.static(__dirname + '/app')); //serving the static HTML app.get("/", function (req, res) { res.sendfile("/index.html"); }); var appData; var db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', function callback() { var dataSchema; dataSchema = mongoose.Schema({ clock: Array, hours: Number, minutes: Number, seconds: Number }); appData = mongoose.model('appData', dataSchema); //Sending and receiving data io.on('connection', function (socket) { fs.watch('data', function (event, filename) { fs.readFile('data/' + filename, function (err, data) { if (!err) { try { var x = JSON.parse(data); socket.emit('updated', x); // Create a new instance of appData model // ie also known as a document var savingData = new appData({ clock: x.clock, hours: x.hours, minutes: x.minutes, seconds: x.seconds }); //save data savingData.save(); } catch (e) { console.log('malformed data'); } } }) }); }); }); 

Мы используем try и catch чтобы предотвратить сбой приложения. Если мы не используем его, а JSON.parse выдает ошибку unexpected user input поскольку иногда данные не полностью читаются из-за высокой скорости изменения, приложение может аварийно завершить работу. Что-то, чего мы хотим избежать!

В качестве дополнительного примечания, убедитесь, что сервер MongoDB запущен или приложение аварийно завершит работу.

Код на стороне клиента

В этом разделе мы создадим простую статическую HTML-страницу. Когда новые данные поступают через socket.io, мы обновляем данные, показанные на странице. Эти данные также можно использовать для создания графиков и диаграмм в реальном времени.

Вот простой код файла index.html :

 <body ng-app="demo" ng-controller="demoController" ng-cloak class="ng-cloak"> <div>{{data.hours}} : {{data.minutes}} : {{data.seconds}}</div> </body> <script src="/path/to/angular.js"></script> <script src='/path/to/socket.io.js'></script> <script> var socket = io.connect(); angular.module('demo', []).controller('demoController', ['$scope', function($scope) { socket.on('updated', function(data) { $scope.$apply(function(){ $scope.data = data; }); }); }]); </script> 

Директива ngCloak используется для предотвращения краткого отображения шаблона AngularJS браузером в исходном (некомпилированном) виде во время загрузки нашего приложения.

Наконец, нам нужно добавить следующий код CSS, чтобы он работал в случае загрузки AngularJS после тела HTML.

 [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } 

Контроллер написан в виде длинной функции, поэтому нам не нужно вводить аргументы.

При получении новых данных нам нужно использовать $scope.apply() для обновления данных в представлении. $scope.apply() принимает функцию или строку выражения AngularJS и выполняет ее. Затем он автоматически вызывает $scope.$digest() для обновления любых наблюдателей. Альтернативой может быть $timeout (предоставляемый AngularJS), который похож на setTimeout но автоматически оборачивает наш код в $apply по умолчанию.

Запуск приложения

Мы должны убедиться, что код MATLAB и сервер MongoDB работают перед запуском сервера Node.js. Чтобы запустить сервер MongoDB, вам нужно выполнить команду mongod на терминале. Чтобы запустить сервер Node.js, вы должны выполнить команду node server.js в корне папки проекта.

Статическая страница, показывающая текущее время, будет отображаться на 127.0.0.1:3000 .

Выводы

В этой статье мы создали веб-приложение, использующее стек MEAN, который получает данные в формате JSON из программы MATLAB. Данные конвертируются с помощью JSONlab. Затем данные отправляются в браузер с помощью socket.io, поэтому изменения в браузере отражаются в режиме реального времени. Полный исходный код этой демонстрации доступен на GitHub .

Я надеюсь, что вам понравилась статья, и я с нетерпением жду ваших комментариев.