diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..028e936 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +src/astron.m +src/zigler_nichols.m +src/relay.m +*.m~ +*.asv +survey +src/easylife.m +sim/ +dc fan/ +web fan/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..195231d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Pedro Martins + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/basic_set.m b/basic_set.m new file mode 100644 index 0000000..806193d --- /dev/null +++ b/basic_set.m @@ -0,0 +1,38 @@ +%% read and press ctrl + enter for each block! +return +clear + +%% libraries (must be at current folder!) +addpath('jsonlab-1.5') + +%% Triangular Pulse Input +nlang = 3; %number of linguistic variables +mixing = 0.5; %from 0 to 1, there are at most two variables (required) +span = 400; %distance beetween edges (input span) + +b = linspace(-1.0, 1.0, nlang)'; +a = b - 1/(nlang - 1)*(1 + mixing)'; +c = b + 1/(nlang - 1)*(1 + mixing)'; +a(1) = -inf; c(end) = inf; %edges +s = struct('params', mat2cell([a b c]*span/2, ones([1 nlang])),... + 'type', 'triangularPulse'); + +%% Triangular Pulse Output +nlang = 5; %number of linguistic variables +mixing = 0.5; %from 0 to 1, there are at most two variables (required) +span = 100; %distance beetween edges (input span) + +b = linspace((1 + mixing)/(2*nlang), 1.0 - (1 + mixing)/(2*nlang), nlang)'; +a = b - (1 + mixing)/(2*nlang)'; +c = b + (1 + mixing)/(2*nlang)'; +s = struct('params', mat2cell([a b c]*span, ones([1 nlang])),... + 'type', 'triangularPulse'); + +%% other distributions @todo + +%% Save JSON +json = savejson('', s); +json([1:2 end-1:end]) = []; +file = fopen('.\fuzzy\membership\fan\u.json', 'w'); +fprintf(file, json); +fclose(file); diff --git a/centroid_area.m b/centroid_area.m new file mode 100644 index 0000000..bdd0f0c --- /dev/null +++ b/centroid_area.m @@ -0,0 +1,27 @@ +function out = centroid_area( params ) +%CENTROID x = centroid( params ) +switch params{end} + case 'triangularPulse' + [h, a, b, c, x] = params{:}; + if isnan(x(1)) && isnan(x(2)) + area = 0; + centroid = 0; + else + S(1) = (b - x(1))*h; + C(1) = (b + x(1))/2; + S(2) = (x(2) - b)*h; + C(2) = (b + x(2))/2; + S(3) = (x(1) - a)*h/2; + C(3) = (a + 2*x(1))/3; + S(4) = (c - x(2))*h/2; + C(4) = (c + 2*x(2))/3; + area = sum(S); + if area ~= 0 + centroid = sum(C.*S)/area; + else + centroid = 0; + end + end +end +out = [centroid area]; +end \ No newline at end of file diff --git a/degrau.slx b/degrau.slx new file mode 100644 index 0000000..9416070 Binary files /dev/null and b/degrau.slx differ diff --git a/fuzzy/fan/README.txt b/fuzzy/fan/README.txt new file mode 100644 index 0000000..38d24be --- /dev/null +++ b/fuzzy/fan/README.txt @@ -0,0 +1,14 @@ +%fan fuzzy uses ../membership/fan json data +%and K is the plant model dc gain + +u(k) = fuzzy(e(k), de(k)); %no model +u(k) = (r(k)/K - 50) + fuzzy(e(k), de(k)); %with model + +Gz = + + 0.07751 z^-1 + 0.1716 z^-2 + ------------------------------ + 1 - 0.8539 z^-1 - 0.02473 z^-2 + +Sample time: 0.1 seconds +Discrete-time transfer function. \ No newline at end of file diff --git a/fuzzy/fan/no_model.fig b/fuzzy/fan/no_model.fig new file mode 100644 index 0000000..d6224f0 Binary files /dev/null and b/fuzzy/fan/no_model.fig differ diff --git a/fuzzy/fan/no_model.jpg b/fuzzy/fan/no_model.jpg new file mode 100644 index 0000000..d5cb6d5 Binary files /dev/null and b/fuzzy/fan/no_model.jpg differ diff --git a/fuzzy/fan/with_model.fig b/fuzzy/fan/with_model.fig new file mode 100644 index 0000000..8faa574 Binary files /dev/null and b/fuzzy/fan/with_model.fig differ diff --git a/fuzzy/fan/with_model.jpg b/fuzzy/fan/with_model.jpg new file mode 100644 index 0000000..ae83014 Binary files /dev/null and b/fuzzy/fan/with_model.jpg differ diff --git a/fuzzy/fan1/README.txt b/fuzzy/fan1/README.txt new file mode 100644 index 0000000..995b830 --- /dev/null +++ b/fuzzy/fan1/README.txt @@ -0,0 +1,14 @@ +%fan1 fuzzy uses ../membership/fan1 json data +%and K is the plant model dc gain + +u(k) = fuzzy(e(k), de(k)); %no model +u(k) = (r(k)/K - 50) + fuzzy(e(k), de(k)); %with model + +Gz = + + 0.07751 z^-1 + 0.1716 z^-2 + ------------------------------ + 1 - 0.8539 z^-1 - 0.02473 z^-2 + +Sample time: 0.1 seconds +Discrete-time transfer function. \ No newline at end of file diff --git a/fuzzy/fan1/no_model.fig b/fuzzy/fan1/no_model.fig new file mode 100644 index 0000000..d8d9065 Binary files /dev/null and b/fuzzy/fan1/no_model.fig differ diff --git a/fuzzy/fan1/no_model.jpg b/fuzzy/fan1/no_model.jpg new file mode 100644 index 0000000..38b9948 Binary files /dev/null and b/fuzzy/fan1/no_model.jpg differ diff --git a/fuzzy/fan1/with_model.fig b/fuzzy/fan1/with_model.fig new file mode 100644 index 0000000..fffc94c Binary files /dev/null and b/fuzzy/fan1/with_model.fig differ diff --git a/fuzzy/fan1/with_model.jpg b/fuzzy/fan1/with_model.jpg new file mode 100644 index 0000000..b845eb7 Binary files /dev/null and b/fuzzy/fan1/with_model.jpg differ diff --git a/fuzzy/membership/fan/de.json b/fuzzy/membership/fan/de.json new file mode 100644 index 0000000..6f92770 --- /dev/null +++ b/fuzzy/membership/fan/de.json @@ -0,0 +1,14 @@ +[ + { + "params": ["-_Inf_",-120,-10], + "type": "triangularPulse" + }, + { + "params": [-30,0,30], + "type": "triangularPulse" + }, + { + "params": [10,120,"_Inf_"], + "type": "triangularPulse" + } +] \ No newline at end of file diff --git a/fuzzy/membership/fan/e.json b/fuzzy/membership/fan/e.json new file mode 100644 index 0000000..4069b9e --- /dev/null +++ b/fuzzy/membership/fan/e.json @@ -0,0 +1,14 @@ +[ + { + "params": ["-_Inf_",-50,-5], + "type": "triangularPulse" + }, + { + "params": [-10,0,10], + "type": "triangularPulse" + }, + { + "params": [5,50,"_Inf_"], + "type": "triangularPulse" + } +] \ No newline at end of file diff --git a/fuzzy/membership/fan/u.json b/fuzzy/membership/fan/u.json new file mode 100644 index 0000000..29ea8e1 --- /dev/null +++ b/fuzzy/membership/fan/u.json @@ -0,0 +1,22 @@ +[ + { + "params": [0,15,30], + "type": "triangularPulse" + }, + { + "params": [17.5,32.5,47.5], + "type": "triangularPulse" + }, + { + "params": [35,50,65], + "type": "triangularPulse" + }, + { + "params": [52.5,67.5,82.5], + "type": "triangularPulse" + }, + { + "params": [70,85,100], + "type": "triangularPulse" + } +] \ No newline at end of file diff --git a/fuzzy/membership/fan1/de.json b/fuzzy/membership/fan1/de.json new file mode 100644 index 0000000..c139e6b --- /dev/null +++ b/fuzzy/membership/fan1/de.json @@ -0,0 +1,14 @@ +[ + { + "params": ["-_Inf_",-250,-10], + "type": "triangularPulse" + }, + { + "params": [-100,0,100], + "type": "triangularPulse" + }, + { + "params": [10,250,"_Inf_"], + "type": "triangularPulse" + } +] \ No newline at end of file diff --git a/fuzzy/membership/fan1/e.json b/fuzzy/membership/fan1/e.json new file mode 100644 index 0000000..2ae852c --- /dev/null +++ b/fuzzy/membership/fan1/e.json @@ -0,0 +1,14 @@ +[ + { + "params": ["-_Inf_",-200,-5], + "type": "triangularPulse" + }, + { + "params": [-25,0,25], + "type": "triangularPulse" + }, + { + "params": [5,200,"_Inf_"], + "type": "triangularPulse" + } +] \ No newline at end of file diff --git a/fuzzy/membership/fan1/u.json b/fuzzy/membership/fan1/u.json new file mode 100644 index 0000000..29ea8e1 --- /dev/null +++ b/fuzzy/membership/fan1/u.json @@ -0,0 +1,22 @@ +[ + { + "params": [0,15,30], + "type": "triangularPulse" + }, + { + "params": [17.5,32.5,47.5], + "type": "triangularPulse" + }, + { + "params": [35,50,65], + "type": "triangularPulse" + }, + { + "params": [52.5,67.5,82.5], + "type": "triangularPulse" + }, + { + "params": [70,85,100], + "type": "triangularPulse" + } +] \ No newline at end of file diff --git a/fuzzy_fan.m b/fuzzy_fan.m new file mode 100644 index 0000000..4d00b88 --- /dev/null +++ b/fuzzy_fan.m @@ -0,0 +1,116 @@ +%1. Right-click the editor's tab and select "Change current folder to..." +%2. Run the code either with Command Window, F5 or Ctrl+Enter +%3. Modify the configuration and repeat from (2) +clc +clear +format shortg +addpath(genpath('src')) +global t y r e u pwm k + +% Adicione o nome de variáveis que queira salvar +salvar = {'t', 'y', 'r', 'e', 'u', 'pwm', 'ping', 'o', 'k', 'n', 'T'}; + +T = 0.1; %tempo de amostragens +n = 300; %numero de amostras +o = 3; %início de amostragem +t = (0:(n-1))*T; %vetor de tempo + +%% I/O +%tenta conectar com a planta, simula caso aconteça algum erro +z = tf('z', T, 'variable', 'z^-1'); +Gz = z^-1*(0.077508 + 0.17161*z^-1)/(1 - 0.8539*z^-1 - 0.02473*z^-2); + +%ajuste a COM e o baud rate de 19200, em Gerenciador de Dispositivos +[termina, leitura, escrita, planta] = startcom('COM20', Gz); + +%% CONFIGURACAO +pasta = planta*'pratica' + ~planta*'teorica'; +salvar_em = ['ventilador/' pasta '/fuzzy']; +saturacao = 100; +referencia = 100; +escala = 200; + +%ESTADO INCIAL +[r, y, e, u, pwm] = deal(zeros(n, 1)); +ping = nan(n, 1); +t0 = tic; + +%% FUZZY UZI +addpath('.\jsonlab-1.5') +pasta_fuzzy = '.\fuzzy\membership\fan1\'; +mfe = membership(loadjson([pasta_fuzzy 'e.json'])); +mfde = membership(loadjson([pasta_fuzzy 'de.json'])); +mfu = membership(loadjson([pasta_fuzzy 'u.json'])); + +AND = @(x1, x2) min(x1, x2); +OR = @(x1, x2) max(x1, x2); +IF = @(y, member) centroid_area([y member(y)]); + +% AND min +% OR max +% IF centroid +% -e & -de = --u +% -e & +de | 0e & -de = -u +% -e & 0de | +e & 0de | 0e & 0de = 0u +% 0e & +de | +e & -de = +u +% +e & +de = ++u + +%% CONTROL LOOP +K = dcgain(Gz); +dr = (escala - referencia)/4; + +for k = 3:n + %MEDIR SENSOR + time = tic; + y(k) = leitura(); + + %REFERÊNCIA + r(k) = referencia + dr*(-1*(k>n/5) + 2*(k>2*n/5) - 3*(k>3*n/5) + 4*(k>4*n/5)); + e(k) = r(k) - y(k); + + %CONTROLE + %fuzzification + fe = mfe.fx(e(k)); + fde = mfde.fx((y(k) - y(k-1))/T); + [ne, ze, pe] = fe{:}; + [nde, zde, pde] = fde{:}; + [nnu, nu, zu, pu, ppu] = mfu.fy{:}; + %rule system + rules = ... + [ + IF(AND(ne, nde), nnu); + IF(OR(OR(AND(ne, pde), AND(ne, zde)), AND(ze, nde)), nu); + IF(AND(ze, zde), zu); + IF(OR(OR(AND(pe, nde), AND(pe, zde)), AND(ze, pde)), pu); + IF(AND(pe, pde), ppu); + ]; + %defuzzification +% u(k) = sum(rules(:,1).*rules(:,2))/sum(rules(:,2)); + u(k) = (r(k)/K - 50) + sum(rules(:,1).*rules(:,2))/sum(rules(:,2)); + + %ATUAÇÃO E SATURAÇÃO + pwm(k) = min(max(u(k), 0), saturacao); + + escrita(pwm(k)); + ping(k) = toc(time); + + %DELAY + if planta + while toc(time) < T + end + end +end +termina(); +fprintf('Tempo: %f segundos\n\n', toc(t0) - toc(time)); + +%% PLOT & SALVE +fig = plotudo(t(o:k), y, r, e, u, pwm, 0, 0, 0); +if ~exist(salvar_em, 'dir') + mkdir(salvar_em); +end +date = datestr(datetime('now')); +date(date == '-' | date == ':') = '_'; +path = [salvar_em '/' date]; +save([path '.mat'], salvar{:}) +saveas(fig, [path '.fig']) +disp(['Plant: ' salvar_em ' Saved at: ' path]) diff --git a/fuzzy_tanque.m b/fuzzy_tanque.m new file mode 100644 index 0000000..a968abb --- /dev/null +++ b/fuzzy_tanque.m @@ -0,0 +1,119 @@ +%1. Right-click the editor's tab and select "Change current folder to..." +%2. Run the code either with Command Window, F5 or Ctrl+Enter +%3. Modify the configuration and repeat from (2) + +clc +clear +format shortg +addpath(genpath('src')) + +global t y r e u pwm k + +% Adicione o nome de variáveis que queira salvar +salvar = {'t', 'y', 'r', 'e', 'u', 'pwm', 'ping', 'o', 'k', 'n', 'T'}; + +T = 1; %tempo de amostragens +n = 600; %numero de amostras +o = 3; %início de amostragem +t = (0:(n-1))*T; %vetor de tempo + +z = tf('z', T, 'variable', 'z^-1'); +Gz = 0.01595/(z-1); +Gz.ioDelay = 1; + +%% I/O +%tenta conectar com a planta, simula caso aconteça algum erro +try + throw('simula'); %descomente para simular + start_easyport; + pause(1) + enable_pump(1); + leitura = @() read_level; + escrita = @(duty) write_pump(duty); + termina = @() end_easyport; + planta = 'pratica'; + leitura(); +catch ME + errors = textscan(ME.message, '%[^\n]', 1); + disp([errors{end}{:}]); + leitura = @() readsim(Gz); + escrita = @(duty) writesim(duty - 3.7); + termina = 0; + planta = 'teoria'; + k = 0; + escrita(0); + leitura(); +end + +%% CONFIGURACAO +salvar_em = [planta, 'pedro/fuzzy']; +saturacao = 9.5; +referencia = 3; + +%ESTADO INCIAL +[r, y, e, u, pwm] = deal(zeros(n, 1)); +ping = nan(n, 1); +t0 = tic; + +%% FUZZY UZI @todo + +% regras +% cada combinação de entrada é realizada pelo: mínimo +% a fuzzificação de cada entrada é combinada pelas regras (x -> y) +% a aplicação de uma regra em uma função é através do: centro de massa (y) +% a ativação de uma função por múltiplas regras é decidida pelo: máximo (y) (inferência) +% a combinação de múltiplas funções é realizada pelo: centro de massa (y -> x) (defuzificação) +% -e, -de = --u +% -e, +de = -u +% 0e, -de = -u +% -e, 0de = 0u +% +e, 0de = 0u +% 0e, +de = +u +% +e, -de = +u +% +e, +de = ++u + +%rule system +%defuzzification + +%% CONTROL LOOP +for k = 3:n + %MEDIR SENSOR + time = tic; + y(k) = leitura(); + + %REFERÊNCIA + r(k) = referencia + 2*(k>n/6) + 2*(k>2*n/6) + 1*(k>3*n/6) - 2*(k>4*n/6) - 2*(k>5*n/6); + e(k) = r(k) - y(k); + + %CONTROLE + u(k) = 5; + + %ATUAÇÃO E SATURAÇÃO + pwm(k) = min(max(u(k), 0), saturacao); + + escrita(pwm(k)); + ping(k) = toc(time); + + %DELAY + if isa(termina, 'function_handle') + while toc(time) < T + end + end +end +fprintf('Tempo: %f segundos\n\n', toc(t0) - toc(time)); + +if exist('pump', 'var') + end_easyport +end + +%% PLOT & SALVE +fig = plotudo(t(o:k), y, r, e, u, pwm, 0, 1, 0); +if ~exist(salvar_em, 'dir') + mkdir(salvar_em); +end +date = datestr(datetime('now')); +date(date == '-' | date == ':') = '_'; +path = [salvar_em '/' date]; +save([path '.mat'], salvar{:}) +saveas(fig, [path '.fig']) +disp(['Plant: ' salvar_em ' Saved at: ' path]) diff --git a/jsonlab-1.5/AUTHORS.txt b/jsonlab-1.5/AUTHORS.txt new file mode 100644 index 0000000..e0bb650 --- /dev/null +++ b/jsonlab-1.5/AUTHORS.txt @@ -0,0 +1,53 @@ +The author of "jsonlab" toolbox is Qianqian Fang. Qianqian +is currently an Assistant Professor in the Department of Bioengineering, +Northeastern University. + +Address: Qianqian Fang + Department of Bioengineering + Northeastern University + 212A Lake Hall + 360 Huntington Ave, Boston, MA 02115, USA + Office: 503 Holmes Hall + Phone[O]: 617-373-3829 +URL: http://fanglab.org +Email: and + + +The script loadjson.m was built upon previous works by + +- Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713 + date: 2009/11/02 +- François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393 + date: 2009/03/22 +- Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565 + date: 2008/07/03 + + +This toolbox contains patches submitted by the following contributors: + +- Blake Johnson + part of revision 341 + +- Niclas Borlin + various fixes in revision 394, including + - loadjson crashes for all-zero sparse matrix. + - loadjson crashes for empty sparse matrix. + - Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson. + - loadjson crashes for sparse real column vector. + - loadjson crashes for sparse complex column vector. + - Data is corrupted by savejson for sparse real row vector. + - savejson crashes for sparse complex row vector. + +- Yul Kang + patches for svn revision 415. + - savejson saves an empty cell array as [] instead of null + - loadjson differentiates an empty struct from an empty array + +- Mykhailo Bratukha + (Pull#14) Bug fix: File path is wrongly inerpreted as JSON string + +- Insik Kim + (Pull#12) Bug fix: Resolving bug that cell type is converted to json with transposed data + +- Sertan Senturk + (Pull#10,#11) Feature: Added matlab object saving to savejson and saveubjson diff --git a/jsonlab-1.5/ChangeLog.txt b/jsonlab-1.5/ChangeLog.txt new file mode 100644 index 0000000..da1e725 --- /dev/null +++ b/jsonlab-1.5/ChangeLog.txt @@ -0,0 +1,106 @@ +============================================================================ + + JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave + +---------------------------------------------------------------------------- + +JSONlab ChangeLog (key features marked by *): + +== JSONlab 1.5 (codename: Nominus - alpha), FangQ neu.edu> == + + 2017/01/02 *use Big-endian format to store floating points (d/D) in saveubjson (Issue #25) + 2017/01/02 *speedup parsing large unstructured data by 2x (Issue #9) + 2017/01/01 make parsing independent of white space (Issue #30) + 2016/08/27 allow to parse array of homogeneous elements (Issue 5) + 2016/08/22 permit [] inside file names in savejson + 2016/01/06 fix a bug that prevents saving to a file in savejson + + +== JSONlab 1.2 (codename: Optimus - Update 2), FangQ neu.edu> == + + 2015/12/16 replacing string concatenation by str cells to gain 2x speed in savejson (Issue#17) + 2015/12/11 fix FileName option case bug (SVN rev#495) + 2015/12/11 add SingletCell option, add SingletArray to replace NoRowBracket (Issue#15,#8) + 2015/11/10 fix bug for inerpreting file names as JSON string - by Mykhailo Bratukha (Pull#14) + 2015/10/16 fix bug for cell with transposed data - by Insik Kim (Pull#12) + 2015/09/25 support exporting matlab object to JSON - by Sertan Senturk (Pull#10, #11) + +== JSONlab 1.1 (codename: Optimus - Update 1), FangQ neu.edu> == + + 2015/05/05 *massively accelerating loadjson for parsing large collection of unstructured small objects + 2015/05/05 force array bracket in 1x1 struct to maintain depth (Issue#1) + 2015/05/05 parse logicals in loadjson + 2015/05/05 make options case insensitive + 2015/05/01 reading unicode encoded json files (thanks to Sertan Senturk,Issue#3) + 2015/04/30 allow \uXXXX to represent a unicode in a string (Issue#2) + 2015/03/30 save a 0x0 solid real empty array as null and handel empty struct array + 2015/03/30 properly handle escape characters in a string + 2015/01/24 *implement the UBJSON Draft12 new name format + 2015/01/13 correct cell array indentation inconsistency + +== JSONlab 1.0 (codename: Optimus - Final), FangQ neu.edu> == + + 2015/01/02 polish help info for all major functions, update examples, finalize 1.0 + 2014/12/19 fix a bug to strictly respect NoRowBracket in savejson + +== JSONlab 1.0.0-RC2 (codename: Optimus - RC2), FangQ neu.edu> == + + 2014/11/22 show progress bar in loadjson ('ShowProgress') + 2014/11/17 *add Compact option in savejson to output compact JSON format ('Compact') + 2014/11/17 add FastArrayParser in loadjson to specify fast parser applicable levels + 2014/09/18 *start official github mirror: https://github.com/fangq/jsonlab + +== JSONlab 1.0.0-RC1 (codename: Optimus - RC1), FangQ neu.edu> == + + 2014/09/17 fix several compatibility issues when running on octave versions 3.2-3.8 + 2014/09/17 *support 2D cell and struct arrays in both savejson and saveubjson + 2014/08/04 escape special characters in a JSON string + 2014/02/16 fix a bug when saving ubjson files + +== JSONlab 0.9.9 (codename: Optimus - beta), FangQ neu.edu> == + + 2014/01/22 use binary read and write in saveubjson and loadubjson + +== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ neu.edu> == + + 2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang) + +== JSONlab 0.9.8 (codename: Optimus - alpha), FangQ neu.edu> == + 2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson + +== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ neu.edu> == + 2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin) + +== JSONlab 0.9.0 (codename: Rodimus), FangQ neu.edu> == + + 2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson + 2012/06/01 support JSONP in savejson + 2012/05/25 fix the empty cell bug (reported by Cyril Davin) + 2012/04/05 savejson can save to a file (suggested by Patrick Rapin) + +== JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ neu.edu> == + + 2012/02/28 loadjson quotation mark escape bug, see http://bit.ly/yyk1nS + 2012/01/25 patch to handle root-less objects, contributed by Blake Johnson + +== JSONlab 0.8.0 (codename: Sentiel), FangQ neu.edu> == + + 2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab + 2012/01/11 remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer + 2011/12/22 *accept sequence of 'param',value input in savejson and loadjson + 2011/11/18 fix struct array bug reported by Mykel Kochenderfer + +== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ neu.edu> == + + 2011/10/21 fix a bug in loadjson, previous code does not use any of the acceleration + 2011/10/20 loadjson supports JSON collections - concatenated JSON objects + +== JSONlab 0.5.0 (codename: Nexus), FangQ neu.edu> == + + 2011/10/16 package and release jsonlab 0.5.0 + 2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug + 2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level + 2011/10/10 create jsonlab project, start jsonlab website, add online documentation + 2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support + 2011/10/06 *savejson works for structs, cells and arrays + 2011/09/09 derive loadjson from JSON parser from MATLAB Central, draft savejson.m diff --git a/jsonlab-1.5/LICENSE_BSD.txt b/jsonlab-1.5/LICENSE_BSD.txt new file mode 100644 index 0000000..3f86af1 --- /dev/null +++ b/jsonlab-1.5/LICENSE_BSD.txt @@ -0,0 +1,25 @@ +Copyright 2011-2017 Qianqian Fang neu.edu>. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the +authors and should not be interpreted as representing official policies, either expressed +or implied, of the copyright holders. diff --git a/jsonlab-1.5/README.txt b/jsonlab-1.5/README.txt new file mode 100644 index 0000000..915985e --- /dev/null +++ b/jsonlab-1.5/README.txt @@ -0,0 +1,431 @@ +=============================================================================== += JSONLab = += An open-source MATLAB/Octave JSON encoder and decoder = +=============================================================================== + +*Copyright (C) 2011-2017 Qianqian Fang +*License: BSD License, see License*.txt +*Version: 1.5 (Nominus - alpha) + +------------------------------------------------------------------------------- + +Table of Content: + +I. Introduction +II. Installation +III.Using JSONLab +IV. Known Issues and TODOs +V. Contribution and feedback + +------------------------------------------------------------------------------- + +I. Introduction + +JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable, +human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format +to represent complex and hierarchical data. It is as powerful as +[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely +used for data-exchange in applications, and is essential for the wild success +of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and +[http://en.wikipedia.org/wiki/Web_2.0 Web2.0]. + +UBJSON (Universal Binary JSON) is a binary JSON format, specifically +optimized for compact file size and better performance while keeping +the semantics as simple as the text-based JSON format. Using the UBJSON +format allows to wrap complex binary data in a flexible and extensible +structure, making it possible to process complex and large dataset +without accuracy loss due to text conversions. + +We envision that both JSON and its binary version will serve as part of +the mainstream data-exchange formats for scientific research in the future. +It will provide the flexibility and generality achieved by other popular +general-purpose file specifications, such as +[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly +reduced complexity and enhanced performance. + +JSONLab is a free and open-source implementation of a JSON/UBJSON encoder +and a decoder in the native MATLAB language. It can be used to convert a MATLAB +data structure (array, struct, cell, struct array and cell array) into +JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB +data structure. JSONLab supports both MATLAB and +[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone). + +------------------------------------------------------------------------------- + +II. Installation + +The installation of JSONLab is no different than any other simple +MATLAB toolbox. You only need to download/unzip the JSONLab package +to a folder, and add the folder's path to MATLAB/Octave's path list +by using the following command: + + addpath('/path/to/jsonlab'); + +If you want to add this path permanently, you need to type "pathtool", +browse to the jsonlab root folder and add to the list, then click "Save". +Then, run "rehash" in MATLAB, and type "which loadjson", if you see an +output, that means JSONLab is installed for MATLAB/Octave. + +------------------------------------------------------------------------------- + +III.Using JSONLab + +JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder, +and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and +two equivallent functions -- loadubjson and saveubjson for the binary +JSON. The detailed help info for the four functions can be found below: + +=== loadjson.m === +
+  data=loadjson(fname,opt)
+     or
+  data=loadjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (q.fang  neu.edu)
+  created on 2011/09/09, including previous works from 
+ 
+          Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+             created on 2009/11/02
+          François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+             created on  2009/03/22
+          Joel Feenstra:
+          http://www.mathworks.com/matlabcentral/fileexchange/20565
+             created on 2008/07/03
+ 
+  $Id$
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a JSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.FastArrayParser [1|0 or integer]: if set to 1, use a
+                          speed-optimized array parser when loading an 
+                          array object. The fast array parser may 
+                          collapse block arrays into a single large
+                          array similar to rules defined in cell2mat; 0 to 
+                          use a legacy parser; if set to a larger-than-1
+                          value, this option will specify the minimum
+                          dimension to enable the fast array parser. For
+                          example, if the input is a 3D array, setting
+                          FastArrayParser to 1 will return a 3D array;
+                          setting to 2 will return a cell array of 2D
+                          arrays; setting to 3 will return to a 2D cell
+                          array of 1D vectors; setting to 4 will return a
+                          3D cell array.
+            opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
+       dat=loadjson(['examples' filesep 'example1.json'])
+       dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
+ 
+  license:
+      BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details 
+ 
+ +=== savejson.m === + +
+  json=savejson(rootname,obj,filename)
+     or
+  json=savejson(rootname,obj,opt)
+  json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+  Object Notation) string
+ 
+  author: Qianqian Fang (q.fang  neu.edu)
+  created on 2011/09/09
+ 
+  $Id$
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array,
+       class instance).
+       filename: a string for the file name to save the output JSON data.
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+                          of a 1D/2D array;
+         opt.ArrayIndent [1|0]: if 1, output explicit data array with
+                          precedent indentation; if 0, no indentation
+         opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.SingletArray [0|1]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.SingletCell  [1|0]: if 1, always enclose a cell with "[]" 
+                          even it has only one element; if 0, brackets
+                          are ignored when a cell has only 1 element.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
+                          to represent +/-Inf. The matched pattern is '([-+]*)Inf'
+                          and $1 represents the sign. For those who want to use
+                          1e999 to represent Inf, they can set opt.Inf to '$11e999'
+         opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
+                          to represent NaN
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSONP='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+         opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
+         opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a string in the JSON format (see http://json.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       savejson('jmesh',jsonmesh)
+       savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
+ 
+  license:
+      BSD License, see LICENSE_BSD.txt files for details
+ 
+ +=== loadubjson.m === + +
+  data=loadubjson(fname,opt)
+     or
+  data=loadubjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (q.fang  neu.edu)
+  created on 2013/08/01
+ 
+  $Id$
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a UBJSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs - the param string is equivallent
+            to a field in opt. opt can have the following 
+            fields (first in [.|.] is the default)
+ 
+            opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
+                          for each element of the JSON data, and group 
+                          arrays based on the cell2mat rules.
+            opt.IntEndian [B|L]: specify the endianness of the integer fields
+                          in the UBJSON input data. B - Big-Endian format for 
+                          integers (as required in the UBJSON specification); 
+                          L - input integer fields are in Little-Endian order.
+            opt.NameIsString [0|1]: for UBJSON Specification Draft 8 or 
+                          earlier versions (JSONLab 1.0 final or earlier), 
+                          the "name" tag is treated as a string. To load 
+                          these UBJSON data, you need to manually set this 
+                          flag to 1.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
+ 
+  examples:
+       obj=struct('string','value','array',[1 2 3]);
+       ubjdata=saveubjson('obj',obj);
+       dat=loadubjson(ubjdata)
+       dat=loadubjson(['examples' filesep 'example1.ubj'])
+       dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
+ 
+  license:
+      BSD License, see LICENSE_BSD.txt files for details 
+
+ +=== saveubjson.m === + +
+  json=saveubjson(rootname,obj,filename)
+     or
+  json=saveubjson(rootname,obj,opt)
+  json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a Universal 
+  Binary JSON (UBJSON) binary string
+ 
+  author: Qianqian Fang (q.fang  neu.edu)
+  created on 2013/08/17
+ 
+  $Id$
+ 
+  input:
+       rootname: the name of the root-object, when set to '', the root name
+         is ignored, however, when opt.ForceRootName is set to 1 (see below),
+         the MATLAB variable name will be used as the root name.
+       obj: a MATLAB object (array, cell, cell array, struct, struct array,
+       class instance)
+       filename: a string for the file name to save the output UBJSON data
+       opt: a struct for additional options, ignore to use default values.
+         opt can have the following fields (first in [.|.] is the default)
+ 
+         opt.FileName [''|string]: a file name to save the output JSON data
+         opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [1|0]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.SingletArray [0|1]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt.SingletCell  [1|0]: if 1, always enclose a cell with "[]" 
+                          even it has only one element; if 0, brackets
+                          are ignored when a cell has only 1 element.
+         opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+                          will use the name of the passed obj variable as the 
+                          root object name; if obj is an expression and 
+                          does not have a name, 'root' will be used; if this 
+                          is set to 0 and rootname is empty, the root level 
+                          will be merged down to the lower level.
+         opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
+                          for example, if opt.JSON='foo', the JSON data is
+                          wrapped inside a function call as 'foo(...);'
+         opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+                          back to the string form
+ 
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt and is case sensitive.
+  output:
+       json: a binary string in the UBJSON format (see http://ubjson.org)
+ 
+  examples:
+       jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+                'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+                'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+                           2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+                'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+                'SpecialData',[nan, inf, -inf]);
+       saveubjson('jsonmesh',jsonmesh)
+       saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
+ 
+  license:
+      BSD License, see LICENSE_BSD.txt files for details
+
+ + +=== examples === + +Under the "examples" folder, you can find several scripts to demonstrate the +basic utilities of JSONLab. Running the "demo_jsonlab_basic.m" script, you +will see the conversions from MATLAB data structure to JSON text and backward. +In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet +and validate the loadjson/savejson functions for regression testing purposes. +Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson +and loadubjson functions for various matlab data structures. + +Please run these examples and understand how JSONLab works before you use +it to process your data. + +------------------------------------------------------------------------------- + +IV. Known Issues and TODOs + +JSONLab has several known limitations. We are striving to make it more general +and robust. Hopefully in a few future releases, the limitations become less. + +Here are the known issues: + +# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays; +# When processing names containing multi-byte characters, Octave and MATLAB \ +can give different field-names; you can use feature('DefaultCharacterSet','latin1') \ +in MATLAB to get consistant results +# savejson can not handle class and dataset. +# saveubjson converts a logical array into a uint8 ([U]) array +# an unofficial N-D array count syntax is implemented in saveubjson. We are \ +actively communicating with the UBJSON spec maintainer to investigate the \ +possibility of making it upstream +# loadubjson can not parse all UBJSON Specification (Draft 9) compliant \ +files, however, it can parse all UBJSON files produced by saveubjson. + +------------------------------------------------------------------------------- + +V. Contribution and feedback + +JSONLab is an open-source project. This means you can not only use it and modify +it as you wish, but also you can contribute your changes back to JSONLab so +that everyone else can enjoy the improvement. For anyone who want to contribute, +please download JSONLab source code from its source code repositories by using the +following command: + + git clone https://github.com/fangq/jsonlab.git jsonlab + +or browsing the github site at + + https://github.com/fangq/jsonlab + +alternatively, if you prefer svn, you can checkout the latest code by using + + svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab + +You can make changes to the files as needed. Once you are satisfied with your +changes, and ready to share it with others, please cd the root directory of +JSONLab, and type + + git diff --no-prefix > yourname_featurename.patch + +or + + svn diff > yourname_featurename.patch + +You then email the .patch file to JSONLab's maintainer, Qianqian Fang, at +the email address shown in the beginning of this file. Qianqian will review +the changes and commit it to the subversion if they are satisfactory. + +We appreciate any suggestions and feedbacks from you. Please use the following +mailing list to report any questions you may have regarding JSONLab: + +https://groups.google.com/forum/?hl=en#!forum/jsonlab-users + +(Subscription to the mailing list is needed in order to post messages). diff --git a/jsonlab-1.5/examples/demo_jsonlab_basic.m b/jsonlab-1.5/examples/demo_jsonlab_basic.m new file mode 100644 index 0000000..d44d4ff --- /dev/null +++ b/jsonlab-1.5/examples/demo_jsonlab_basic.m @@ -0,0 +1,181 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Demonstration of Basic Utilities of JSONlab +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +rngstate = rand ('state'); +randseed=hex2dec('623F9A9E'); +clear data2json json2data + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a simple scalar value \n') +fprintf(1,'%%=================================================\n\n') + +data2json=pi +savejson('',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a complex number\n') +fprintf(1,'%%=================================================\n\n') + +clear i; +data2json=1+2*i +savejson('',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a complex matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=magic(6); +data2json=data2json(:,1:3)+data2json(:,4:6)*i +savejson('',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% MATLAB special constants\n') +fprintf(1,'%%=================================================\n\n') + +data2json=[NaN Inf -Inf] +savejson('specials',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a real sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sprand(10,10,0.1) +savejson('sparse',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a complex sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=data2json-data2json*i +savejson('complex_sparse',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an all-zero sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse(2,3); +savejson('all_zero_sparse',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an empty sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse([]); +savejson('empty_sparse',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an empty 0-by-0 real matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=[]; +savejson('empty_0by0_real',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an empty 0-by-3 real matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=zeros(0,3); +savejson('empty_0by3_real',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse real column vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse([0,3,0,1,4]'); +savejson('sparse_column_vector',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse complex column vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=data2json-1i*data2json; +savejson('complex_sparse_column_vector',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse real row vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse([0,3,0,1,4]); +savejson('sparse_row_vector',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse complex row vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=data2json-1i*data2json; +savejson('complex_sparse_row_vector',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a structure\n') +fprintf(1,'%%=================================================\n\n') + +data2json=struct('name','Think Different','year',1997,'magic',magic(3),... + 'misfits',[Inf,NaN],'embedded',struct('left',true,'right',false)) +savejson('astruct',data2json,struct('ParseLogical',1)) +json2data=loadjson(ans) +class(json2data.astruct.embedded.left) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a structure array\n') +fprintf(1,'%%=================================================\n\n') + +data2json=struct('name','Nexus Prime','rank',9); +data2json(2)=struct('name','Sentinel Prime','rank',9); +data2json(3)=struct('name','Optimus Prime','rank',9); +savejson('Supreme Commander',data2json) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a cell array\n') +fprintf(1,'%%=================================================\n\n') + +data2json=cell(3,1); +data2json{1}=struct('buzz',1.1,'rex',1.2,'bo',1.3,'hamm',2.0,'slink',2.1,'potato',2.2,... + 'woody',3.0,'sarge',3.1,'etch',4.0,'lenny',5.0,'squeeze',6.0,'wheezy',7.0); +data2json{2}=struct('Ubuntu',['Kubuntu';'Xubuntu';'Lubuntu']); +data2json{3}=[10.04,10.10,11.04,11.10] +savejson('debian',data2json,struct('FloatFormat','%.2f')) +json2data=loadjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% invalid field-name handling\n') +fprintf(1,'%%=================================================\n\n') + +json2data=loadjson('{"ValidName":1, "_InvalidName":2, ":Field:":3, "项目":"ç»å¯†"}') + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a 2D cell array\n') +fprintf(1,'%%=================================================\n\n') + +data2json={{1,{2,3}},{4,5},{6};{7},{8,9},{10}}; +savejson('data2json',data2json) +json2data=loadjson(ans) % only savejson works for cell arrays, loadjson has issues + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a 2D struct array\n') +fprintf(1,'%%=================================================\n\n') + +data2json=repmat(struct('idx',0,'data','structs'),[2,3]) +for i=1:6 + data2json(i).idx=i; +end +savejson('data2json',data2json) +json2data=loadjson(ans) + +rand ('state',rngstate); + diff --git a/jsonlab-1.5/examples/demo_ubjson_basic.m b/jsonlab-1.5/examples/demo_ubjson_basic.m new file mode 100644 index 0000000..0c35433 --- /dev/null +++ b/jsonlab-1.5/examples/demo_ubjson_basic.m @@ -0,0 +1,180 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Demonstration of Basic Utilities of JSONlab +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +rngstate = rand ('state'); +randseed=hex2dec('623F9A9E'); +clear data2json json2data + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a simple scalar value \n') +fprintf(1,'%%=================================================\n\n') + +data2json=pi +saveubjson('',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a complex number\n') +fprintf(1,'%%=================================================\n\n') + +clear i; +data2json=1+2*i +saveubjson('',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a complex matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=magic(6); +data2json=data2json(:,1:3)+data2json(:,4:6)*i +saveubjson('',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% MATLAB special constants\n') +fprintf(1,'%%=================================================\n\n') + +data2json=[NaN Inf -Inf] +saveubjson('specials',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a real sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sprand(10,10,0.1) +saveubjson('sparse',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a complex sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=data2json-data2json*i +saveubjson('complex_sparse',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an all-zero sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse(2,3); +saveubjson('all_zero_sparse',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an empty sparse matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse([]); +saveubjson('empty_sparse',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an empty 0-by-0 real matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=[]; +saveubjson('empty_0by0_real',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% an empty 0-by-3 real matrix\n') +fprintf(1,'%%=================================================\n\n') + +data2json=zeros(0,3); +saveubjson('empty_0by3_real',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse real column vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse([0,3,0,1,4]'); +saveubjson('sparse_column_vector',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse complex column vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=data2json-1i*data2json; +saveubjson('complex_sparse_column_vector',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse real row vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=sparse([0,3,0,1,4]); +saveubjson('sparse_row_vector',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a sparse complex row vector\n') +fprintf(1,'%%=================================================\n\n') + +data2json=data2json-1i*data2json; +saveubjson('complex_sparse_row_vector',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a structure\n') +fprintf(1,'%%=================================================\n\n') + +data2json=struct('name','Think Different','year',1997,'magic',magic(3),... + 'misfits',[Inf,NaN],'embedded',struct('left',true,'right',false)) +saveubjson('astruct',data2json,struct('ParseLogical',1)) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a structure array\n') +fprintf(1,'%%=================================================\n\n') + +data2json=struct('name','Nexus Prime','rank',9); +data2json(2)=struct('name','Sentinel Prime','rank',9); +data2json(3)=struct('name','Optimus Prime','rank',9); +saveubjson('Supreme Commander',data2json) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a cell array\n') +fprintf(1,'%%=================================================\n\n') + +data2json=cell(3,1); +data2json{1}=struct('buzz',1.1,'rex',1.2,'bo',1.3,'hamm',2.0,'slink',2.1,'potato',2.2,... + 'woody',3.0,'sarge',3.1,'etch',4.0,'lenny',5.0,'squeeze',6.0,'wheezy',7.0); +data2json{2}=struct('Ubuntu',['Kubuntu';'Xubuntu';'Lubuntu']); +data2json{3}=[10.04,10.10,11.04,11.10] +saveubjson('debian',data2json,struct('FloatFormat','%.2f')) +json2data=loadubjson(ans) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% invalid field-name handling\n') +fprintf(1,'%%=================================================\n\n') + +json2data=loadubjson(saveubjson('',loadjson('{"ValidName":1, "_InvalidName":2, ":Field:":3, "项目":"ç»å¯†"}'))) + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a 2D cell array\n') +fprintf(1,'%%=================================================\n\n') + +data2json={{1,{2,3}},{4,5},{6};{7},{8,9},{10}}; +saveubjson('data2json',data2json) +json2data=loadubjson(ans) % only savejson works for cell arrays, loadjson has issues + +fprintf(1,'\n%%=================================================\n') +fprintf(1,'%% a 2D struct array\n') +fprintf(1,'%%=================================================\n\n') + +data2json=repmat(struct('idx',0,'data','structs'),[2,3]) +for i=1:6 + data2json(i).idx=i; +end +saveubjson('data2json',data2json) +json2data=loadubjson(ans) + +rand ('state',rngstate); + diff --git a/jsonlab-1.5/examples/example1.json b/jsonlab-1.5/examples/example1.json new file mode 100644 index 0000000..be0993e --- /dev/null +++ b/jsonlab-1.5/examples/example1.json @@ -0,0 +1,23 @@ + { + "firstName": "John", + "lastName": "Smith", + "age": 25, + "address": + { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021" + }, + "phoneNumber": + [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "fax", + "number": "646 555-4567" + } + ] + } diff --git a/jsonlab-1.5/examples/example2.json b/jsonlab-1.5/examples/example2.json new file mode 100644 index 0000000..eacfbf5 --- /dev/null +++ b/jsonlab-1.5/examples/example2.json @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} diff --git a/jsonlab-1.5/examples/example3.json b/jsonlab-1.5/examples/example3.json new file mode 100644 index 0000000..f52661b --- /dev/null +++ b/jsonlab-1.5/examples/example3.json @@ -0,0 +1,11 @@ +{"menu": { + "id": "file", + "value": "_&File", + "popup": { + "menuitem": [ + {"value": "_&New", "onclick": "CreateNewDoc(\"'\\\"Untitled\\\"'\")"}, + {"value": "_&Open", "onclick": "OpenDoc()"}, + {"value": "_&Close", "onclick": "CloseDoc()"} + ] + } +}} diff --git a/jsonlab-1.5/examples/example4.json b/jsonlab-1.5/examples/example4.json new file mode 100644 index 0000000..1872c12 --- /dev/null +++ b/jsonlab-1.5/examples/example4.json @@ -0,0 +1,35 @@ +[ + { + "sample" : { + "rho" : 1 + } + }, + { + "sample" : { + "rho" : 2 + } + }, + [ + { + "_ArrayType_" : "double", + "_ArraySize_" : [1,2], + "_ArrayData_" : [1,0] + }, + { + "_ArrayType_" : "double", + "_ArraySize_" : [1,2], + "_ArrayData_" : [1,1] + }, + { + "_ArrayType_" : "double", + "_ArraySize_" : [1,2], + "_ArrayData_" : [1,2] + } + ], + [ + "Paper", + "Scissors", + "Stone" + ], + ["a", "b\\", "c\"","d\\\"","e\"[","f\\\"[","g[\\","h[\\\""] +] diff --git a/jsonlab-1.5/examples/jsonlab_basictest.matlab b/jsonlab-1.5/examples/jsonlab_basictest.matlab new file mode 100644 index 0000000..4bd16fa --- /dev/null +++ b/jsonlab-1.5/examples/jsonlab_basictest.matlab @@ -0,0 +1,671 @@ + + < M A T L A B (R) > + Copyright 1984-2010 The MathWorks, Inc. + Version 7.11.0.584 (R2010b) 64-bit (glnxa64) + August 16, 2010 + + + To get started, type one of these: helpwin, helpdesk, or demo. + For product information, visit www.mathworks.com. + +>> >> >> >> >> >> >> >> >> +%================================================= +>> % a simple scalar value +>> %================================================= + +>> >> +data2json = + + 3.1416 + +>> +ans = + +[3.141592654] + + +>> +json2data = + + 3.1416 + +>> >> +%================================================= +>> % a complex number +>> %================================================= + +>> >> >> +data2json = + + 1.0000 + 2.0000i + +>> +ans = + +{ + "_ArrayType_": "double", + "_ArraySize_": [1,1], + "_ArrayIsComplex_": 1, + "_ArrayData_": [1,2] +} + + +>> +json2data = + + 1.0000 + 2.0000i + +>> >> +%================================================= +>> % a complex matrix +>> %================================================= + +>> >> >> +data2json = + + 35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i + 3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i + 31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i + 8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i + 30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i + 4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i + +>> +ans = + +{ + "_ArrayType_": "double", + "_ArraySize_": [6,3], + "_ArrayIsComplex_": 1, + "_ArrayData_": [ + [35,26], + [3,21], + [31,22], + [8,17], + [30,12], + [4,13], + [1,19], + [32,23], + [9,27], + [28,10], + [5,14], + [36,18], + [6,24], + [7,25], + [2,20], + [33,15], + [34,16], + [29,11] + ] +} + + +>> +json2data = + + 35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i + 3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i + 31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i + 8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i + 30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i + 4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i + +>> >> +%================================================= +>> % MATLAB special constants +>> %================================================= + +>> >> +data2json = + + NaN Inf -Inf + +>> +ans = + +{ + "specials": ["_NaN_","_Inf_","-_Inf_"] +} + + +>> +json2data = + + specials: [NaN Inf -Inf] + +>> >> +%================================================= +>> % a real sparse matrix +>> %================================================= + +>> >> +data2json = + + (1,2) 0.6557 + (9,2) 0.7577 + (3,5) 0.8491 + (10,5) 0.7431 + (10,8) 0.3922 + (7,9) 0.6787 + (2,10) 0.0357 + (6,10) 0.9340 + (10,10) 0.6555 + +>> +ans = + +{ + "sparse": { + "_ArrayType_": "double", + "_ArraySize_": [10,10], + "_ArrayIsSparse_": 1, + "_ArrayData_": [ + [1,2,0.6557406992], + [9,2,0.7577401306], + [3,5,0.8491293059], + [10,5,0.7431324681], + [10,8,0.3922270195], + [7,9,0.6787351549], + [2,10,0.03571167857], + [6,10,0.9339932478], + [10,10,0.6554778902] + ] + } +} + + +>> +json2data = + + sparse: [10x10 double] + +>> >> +%================================================= +>> % a complex sparse matrix +>> %================================================= + +>> >> +data2json = + + (1,2) 0.6557 - 0.6557i + (9,2) 0.7577 - 0.7577i + (3,5) 0.8491 - 0.8491i + (10,5) 0.7431 - 0.7431i + (10,8) 0.3922 - 0.3922i + (7,9) 0.6787 - 0.6787i + (2,10) 0.0357 - 0.0357i + (6,10) 0.9340 - 0.9340i + (10,10) 0.6555 - 0.6555i + +>> +ans = + +{ + "complex_sparse": { + "_ArrayType_": "double", + "_ArraySize_": [10,10], + "_ArrayIsComplex_": 1, + "_ArrayIsSparse_": 1, + "_ArrayData_": [ + [1,2,0.6557406992,-0.6557406992], + [9,2,0.7577401306,-0.7577401306], + [3,5,0.8491293059,-0.8491293059], + [10,5,0.7431324681,-0.7431324681], + [10,8,0.3922270195,-0.3922270195], + [7,9,0.6787351549,-0.6787351549], + [2,10,0.03571167857,-0.03571167857], + [6,10,0.9339932478,-0.9339932478], + [10,10,0.6554778902,-0.6554778902] + ] + } +} + + +>> +json2data = + + complex_sparse: [10x10 double] + +>> >> +%================================================= +>> % an all-zero sparse matrix +>> %================================================= + +>> >> >> +ans = + +{ + "all_zero_sparse": { + "_ArrayType_": "double", + "_ArraySize_": [2,3], + "_ArrayIsSparse_": 1, + "_ArrayData_": null + } +} + + +>> +json2data = + + all_zero_sparse: [2x3 double] + +>> >> +%================================================= +>> % an empty sparse matrix +>> %================================================= + +>> >> >> +ans = + +{ + "empty_sparse": { + "_ArrayType_": "double", + "_ArraySize_": [0,0], + "_ArrayIsSparse_": 1, + "_ArrayData_": null + } +} + + +>> +json2data = + + empty_sparse: [] + +>> >> +%================================================= +>> % an empty 0-by-0 real matrix +>> %================================================= + +>> >> >> +ans = + +{ + "empty_0by0_real": null +} + + +>> +json2data = + + empty_0by0_real: [] + +>> >> +%================================================= +>> % an empty 0-by-3 real matrix +>> %================================================= + +>> >> >> +ans = + +{ + "empty_0by3_real": { + "_ArrayType_": "double", + "_ArraySize_": [0,3], + "_ArrayData_": null + } +} + + +>> +json2data = + + empty_0by3_real: [0x3 double] + +>> >> +%================================================= +>> % a sparse real column vector +>> %================================================= + +>> >> >> +ans = + +{ + "sparse_column_vector": { + "_ArrayType_": "double", + "_ArraySize_": [5,1], + "_ArrayIsSparse_": 1, + "_ArrayData_": [ + [2,3], + [4,1], + [5,4] + ] + } +} + + +>> +json2data = + + sparse_column_vector: [5x1 double] + +>> >> +%================================================= +>> % a sparse complex column vector +>> %================================================= + +>> >> >> +ans = + +{ + "complex_sparse_column_vector": { + "_ArrayType_": "double", + "_ArraySize_": [5,1], + "_ArrayIsComplex_": 1, + "_ArrayIsSparse_": 1, + "_ArrayData_": [ + [2,3,-3], + [4,1,-1], + [5,4,-4] + ] + } +} + + +>> +json2data = + + complex_sparse_column_vector: [5x1 double] + +>> >> +%================================================= +>> % a sparse real row vector +>> %================================================= + +>> >> >> +ans = + +{ + "sparse_row_vector": { + "_ArrayType_": "double", + "_ArraySize_": [1,5], + "_ArrayIsSparse_": 1, + "_ArrayData_": [ + [2,3], + [4,1], + [5,4] + ] + } +} + + +>> +json2data = + + sparse_row_vector: [0 3 0 1 4] + +>> >> +%================================================= +>> % a sparse complex row vector +>> %================================================= + +>> >> >> +ans = + +{ + "complex_sparse_row_vector": { + "_ArrayType_": "double", + "_ArraySize_": [1,5], + "_ArrayIsComplex_": 1, + "_ArrayIsSparse_": 1, + "_ArrayData_": [ + [2,3,-3], + [4,1,-1], + [5,4,-4] + ] + } +} + + +>> +json2data = + + complex_sparse_row_vector: [1x5 double] + +>> >> +%================================================= +>> % a structure +>> %================================================= + +>> >> +data2json = + + name: 'Think Different' + year: 1997 + magic: [3x3 double] + misfits: [Inf NaN] + embedded: [1x1 struct] + +>> +ans = + +{ + "astruct": { + "name": "Think Different", + "year": 1997, + "magic": [ + [8,1,6], + [3,5,7], + [4,9,2] + ], + "misfits": ["_Inf_","_NaN_"], + "embedded": { + "left": true, + "right": false + } + } +} + + +>> +json2data = + + astruct: [1x1 struct] + +>> +ans = + +logical + +>> >> +%================================================= +>> % a structure array +>> %================================================= + +>> >> >> >> >> +ans = + +{ + "Supreme Commander": [ + { + "name": "Nexus Prime", + "rank": 9 + }, + { + "name": "Sentinel Prime", + "rank": 9 + }, + { + "name": "Optimus Prime", + "rank": 9 + } + ] +} + + +>> +json2data = + + Supreme_0x20_Commander: {[1x1 struct] [1x1 struct] [1x1 struct]} + +>> >> +%================================================= +>> % a cell array +>> %================================================= + +>> >> >> >> >> +data2json = + + [1x1 struct] + [1x1 struct] + [1x4 double] + +>> +ans = + +{ + "debian": [ + [ + { + "buzz": 1.10, + "rex": 1.20, + "bo": 1.30, + "hamm": 2.00, + "slink": 2.10, + "potato": 2.20, + "woody": 3.00, + "sarge": 3.10, + "etch": 4.00, + "lenny": 5.00, + "squeeze": 6.00, + "wheezy": 7.00 + } + ], + [ + { + "Ubuntu": [ + "Kubuntu", + "Xubuntu", + "Lubuntu" + ] + } + ], + [ + [10.04,10.10,11.04,11.10] + ] + ] +} + + +>> +json2data = + + debian: {{1x1 cell} {1x1 cell} [10.0400 10.1000 11.0400 11.1000]} + +>> >> +%================================================= +>> % invalid field-name handling +>> %================================================= + +>> >> +json2data = + + ValidName: 1 + x0x5F_InvalidName: 2 + x0x3A_Field_0x3A_: 3 + x0xE9A1B9__0xE79BAE_: 'ç»å¯†' + +>> >> +%================================================= +>> % a 2D cell array +>> %================================================= + +>> >> >> +ans = + +{ + "data2json": [ + [ + [ + 1, + [ + 2, + 3 + ] + ], + [ + 4, + 5 + ], + [ + 6 + ] + ], + [ + [ + 7 + ], + [ + 8, + 9 + ], + [ + 10 + ] + ] + ] +} + + +>> +json2data = + + data2json: {{3x1 cell} {3x1 cell}} + +>> >> +%================================================= +>> % a 2D struct array +>> %================================================= + +>> >> +data2json = + +2x3 struct array with fields: + idx + data + +>> >> +ans = + +{ + "data2json": [ + [ + { + "idx": 1, + "data": "structs" + }, + { + "idx": 2, + "data": "structs" + } + ], + [ + { + "idx": 3, + "data": "structs" + }, + { + "idx": 4, + "data": "structs" + } + ], + [ + { + "idx": 5, + "data": "structs" + }, + { + "idx": 6, + "data": "structs" + } + ] + ] +} + + +>> +json2data = + + data2json: {{1x2 cell} {1x2 cell} {1x2 cell}} + +>> >> >> >> \ No newline at end of file diff --git a/jsonlab-1.5/examples/jsonlab_selftest.m b/jsonlab-1.5/examples/jsonlab_selftest.m new file mode 100644 index 0000000..27aee24 --- /dev/null +++ b/jsonlab-1.5/examples/jsonlab_selftest.m @@ -0,0 +1,27 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Regression Test Unit of loadjson and savejson +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +for i=1:4 + fname=sprintf('example%d.json',i); + if(exist(fname,'file')==0) break; end + fprintf(1,'===============================================\n>> %s\n',fname); + json=savejson('data',loadjson(fname)); + fprintf(1,'%s\n',json); + fprintf(1,'%s\n',savejson('data',loadjson(fname),'Compact',1)); + data=loadjson(json); + savejson('data',data,'selftest.json'); + data=loadjson('selftest.json'); +end + +for i=1:4 + fname=sprintf('example%d.json',i); + if(exist(fname,'file')==0) break; end + fprintf(1,'===============================================\n>> %s\n',fname); + json=saveubjson('data',loadjson(fname)); + fprintf(1,'%s\n',json); + data=loadubjson(json); + savejson('',data); + saveubjson('data',data,'selftest.ubj'); + data=loadubjson('selftest.ubj'); +end diff --git a/jsonlab-1.5/examples/jsonlab_selftest.matlab b/jsonlab-1.5/examples/jsonlab_selftest.matlab new file mode 100644 index 0000000..ac652c5 --- /dev/null +++ b/jsonlab-1.5/examples/jsonlab_selftest.matlab @@ -0,0 +1,154 @@ + + < M A T L A B (R) > + Copyright 1984-2010 The MathWorks, Inc. + Version 7.11.0.584 (R2010b) 64-bit (glnxa64) + August 16, 2010 + + + To get started, type one of these: helpwin, helpdesk, or demo. + For product information, visit www.mathworks.com. + +>> >> >> >> >> =============================================== +>> example1.json +{ + "data": { + "firstName": "John", + "lastName": "Smith", + "age": 25, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021" + }, + "phoneNumber": [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "fax", + "number": "646 555-4567" + } + ] + } +} + +{"data": {"firstName": "John","lastName": "Smith","age": 25,"address": {"streetAddress": "21 2nd Street","city": "New York","state": "NY","postalCode": "10021"},"phoneNumber": [{"type": "home","number": "212 555-1234"},{"type": "fax","number": "646 555-4567"}]}} + +=============================================== +>> example2.json +{ + "data": { + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": [ + "GML", + "XML" + ] + }, + "GlossSee": "markup" + } + } + } + } + } +} + +{"data": {"glossary": {"title": "example glossary","GlossDiv": {"title": "S","GlossList": {"GlossEntry": {"ID": "SGML","SortAs": "SGML","GlossTerm": "Standard Generalized Markup Language","Acronym": "SGML","Abbrev": "ISO 8879:1986","GlossDef": {"para": "A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso": ["GML","XML"]},"GlossSee": "markup"}}}}}} + +=============================================== +>> example3.json +{ + "data": { + "menu": { + "id": "file", + "value": "_&File", + "popup": { + "menuitem": [ + { + "value": "_&New", + "onclick": "CreateNewDoc(\"'\\\"Untitled\\\"'\")" + }, + { + "value": "_&Open", + "onclick": "OpenDoc()" + }, + { + "value": "_&Close", + "onclick": "CloseDoc()" + } + ] + } + } + } +} + +{"data": {"menu": {"id": "file","value": "_&File","popup": {"menuitem": [{"value": "_&New","onclick": "CreateNewDoc(\"'\\\"Untitled\\\"'\")"},{"value": "_&Open","onclick": "OpenDoc()"},{"value": "_&Close","onclick": "CloseDoc()"}]}}}} + +=============================================== +>> example4.json +{ + "data": [ + { + "sample": { + "rho": 1 + } + }, + { + "sample": { + "rho": 2 + } + }, + [ + [1,0], + [1,1], + [1,2] + ], + [ + "Paper", + "Scissors", + "Stone" + ], + [ + "a", + "b\\", + "c\"", + "d\\\"", + "e\"[", + "f\\\"[", + "g[\\", + "h[\\\"" + ] + ] +} + +{"data": [{"sample": {"rho": 1}},{"sample": {"rho": 2}},[[1,0],[1,1],[1,2]],["Paper","Scissors","Stone"],["a","b\\","c\"","d\\\"","e\"[","f\\\"[","g[\\","h[\\\""]]} + +>> >> =============================================== +>> example1.json +{Udata{U firstNameSUJohnUlastNameSUSmithUageiUaddress{U streetAddressSU 21 2nd StreetUcitySUNew YorkUstateSUNYU +postalCodeSU10021}U phoneNumber[{UtypeSUhomeUnumberSU 212 555-1234}{UtypeSUfaxUnumberSU 646 555-4567}]}} +=============================================== +>> example2.json +{Udata{Uglossary{UtitleSUexample glossaryUGlossDiv{UtitleCSU GlossList{U +GlossEntry{UIDSUSGMLUSortAsSUSGMLU GlossTermSU$Standard Generalized Markup LanguageUAcronymSUSGMLUAbbrevSU ISO 8879:1986UGlossDef{UparaSUHA meta-markup language, used to create markup languages such as DocBook.U GlossSeeAlso[SUGMLSUXML]}UGlossSeeSUmarkup}}}}}} +=============================================== +>> example3.json +{Udata{Umenu{UidSUfileUvalueSU_&FileUpopup{Umenuitem[{UvalueSU_&NewUonclickSUCreateNewDoc("'\"Untitled\"'")}{UvalueSU_&OpenUonclickSU OpenDoc()}{UvalueSU_&CloseUonclickSU +CloseDoc()}]}}}} +=============================================== +>> example4.json +{Udata[{Usample{Urhoi}}{Usample{Urhoi}}[[$i#U[$i#U[$i#U][SUPaperSUScissorsSUStone][CaSUb\SUc"SUd\"SUe"[SUf\"[SUg[\SUh[\"]]} +>> \ No newline at end of file diff --git a/jsonlab-1.5/examples/jsonlab_speedtest.m b/jsonlab-1.5/examples/jsonlab_speedtest.m new file mode 100644 index 0000000..4990fba --- /dev/null +++ b/jsonlab-1.5/examples/jsonlab_speedtest.m @@ -0,0 +1,21 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Benchmarking processing speed of savejson and loadjson +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +datalen=[1e3 1e4 1e5 1e6]; +len=length(datalen); +tsave=zeros(len,1); +tload=zeros(len,1); +for i=1:len + tic; + json=savejson('data',struct('d1',rand(datalen(i),3),'d2',rand(datalen(i),3)>0.5)); + tsave(i)=toc; + data=loadjson(json); + tload(i)=toc-tsave(i); + fprintf(1,'matrix size: %d\n',datalen(i)); +end + +loglog(datalen,tsave,'o-',datalen,tload,'r*-'); +legend('savejson runtime (s)','loadjson runtime (s)'); +xlabel('array size'); +ylabel('running time (s)'); diff --git a/jsonlab-1.5/jsonopt.m b/jsonlab-1.5/jsonopt.m new file mode 100644 index 0000000..6ed812a --- /dev/null +++ b/jsonlab-1.5/jsonopt.m @@ -0,0 +1,35 @@ +function val=jsonopt(key,default,varargin) +% +% val=jsonopt(key,default,optstruct) +% +% setting options based on a struct. The struct can be produced +% by varargin2struct from a list of 'param','value' pairs +% +% authors:Qianqian Fang (q.fang neu.edu) +% +% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $ +% +% input: +% key: a string with which one look up a value from a struct +% default: if the key does not exist, return default +% optstruct: a struct where each sub-field is a key +% +% output: +% val: if key exists, val=optstruct.key; otherwise val=default +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +val=default; +if(nargin<=2) return; end +opt=varargin{1}; +if(isstruct(opt)) + if(isfield(opt,key)) + val=getfield(opt,key); + elseif(isfield(opt,lower(key))) + val=getfield(opt,lower(key)); + end +end diff --git a/jsonlab-1.5/loadjson.m b/jsonlab-1.5/loadjson.m new file mode 100644 index 0000000..5ef5d48 --- /dev/null +++ b/jsonlab-1.5/loadjson.m @@ -0,0 +1,503 @@ +function data = loadjson(fname,varargin) +% +% data=loadjson(fname,opt) +% or +% data=loadjson(fname,'param1',value1,'param2',value2,...) +% +% parse a JSON (JavaScript Object Notation) file or string +% +% authors:Qianqian Fang (q.fang neu.edu) +% created on 2011/09/09, including previous works from +% +% Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713 +% created on 2009/11/02 +% François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393 +% created on 2009/03/22 +% Joel Feenstra: +% http://www.mathworks.com/matlabcentral/fileexchange/20565 +% created on 2008/07/03 +% +% $Id$ +% +% input: +% fname: input file name, if fname contains "{}" or "[]", fname +% will be interpreted as a JSON string +% opt: a struct to store parsing options, opt can be replaced by +% a list of ('param',value) pairs - the param string is equivallent +% to a field in opt. opt can have the following +% fields (first in [.|.] is the default) +% +% opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat +% for each element of the JSON data, and group +% arrays based on the cell2mat rules. +% opt.FastArrayParser [1|0 or integer]: if set to 1, use a +% speed-optimized array parser when loading an +% array object. The fast array parser may +% collapse block arrays into a single large +% array similar to rules defined in cell2mat; 0 to +% use a legacy parser; if set to a larger-than-1 +% value, this option will specify the minimum +% dimension to enable the fast array parser. For +% example, if the input is a 3D array, setting +% FastArrayParser to 1 will return a 3D array; +% setting to 2 will return a cell array of 2D +% arrays; setting to 3 will return to a 2D cell +% array of 1D vectors; setting to 4 will return a +% 3D cell array. +% opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar. +% +% output: +% dat: a cell array, where {...} blocks are converted into cell arrays, +% and [...] are converted to arrays +% +% examples: +% dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}') +% dat=loadjson(['examples' filesep 'example1.json']) +% dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1) +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +global pos index_esc isoct arraytoken + +if(regexp(fname,'^\s*(?:\[.*\])|(?:\{.*\})\s*$','once')) + string=fname; +elseif(exist(fname,'file')) + try + string = fileread(fname); + catch + try + string = urlread(['file://',fname]); + catch + string = urlread(['file://',fullfile(pwd,fname)]); + end + end +else + error('input file does not exist'); +end + +pos = 1; len = length(string); inStr = string; +isoct=exist('OCTAVE_VERSION','builtin'); +arraytoken=find(inStr=='[' | inStr==']' | inStr=='"'); +jstr=regexprep(inStr,'\\\\',' '); +escquote=regexp(jstr,'\\"'); +arraytoken=sort([arraytoken escquote]); + +% String delimiters and escape chars identified to improve speed: +esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]'); +index_esc = 1; + +opt=varargin2struct(varargin{:}); + +if(jsonopt('ShowProgress',0,opt)==1) + opt.progressbar_=waitbar(0,'loading ...'); +end +jsoncount=1; +while pos <= len + switch(next_char(inStr)) + case '{' + data{jsoncount} = parse_object(inStr, esc, opt); + case '[' + data{jsoncount} = parse_array(inStr, esc, opt); + otherwise + error_pos('Outer level structure must be an object or an array',inStr); + end + jsoncount=jsoncount+1; +end % while + +jsoncount=length(data); +if(jsoncount==1 && iscell(data)) + data=data{1}; +end + +if(isfield(opt,'progressbar_')) + close(opt.progressbar_); +end + +%%------------------------------------------------------------------------- +function object = parse_object(inStr, esc, varargin) + parse_char(inStr, '{'); + object = []; + if next_char(inStr) ~= '}' + while 1 + str = parseStr(inStr, esc, varargin{:}); + if isempty(str) + error_pos('Name of value at position %d cannot be empty',inStr); + end + parse_char(inStr, ':'); + val = parse_value(inStr, esc, varargin{:}); + object.(valid_field(str))=val; + if next_char(inStr) == '}' + break; + end + parse_char(inStr, ','); + end + end + parse_char(inStr, '}'); + if(isstruct(object)) + object=struct2jdata(object); + end + +%%------------------------------------------------------------------------- + +function object = parse_array(inStr, esc, varargin) % JSON array is written in row-major order + global pos isoct + parse_char(inStr, '['); + object = cell(0, 1); + dim2=[]; + arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:}); + pbar=-1; + if(isfield(varargin{1},'progressbar_')) + pbar=varargin{1}.progressbar_; + end + + if next_char(inStr) ~= ']' + if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:})) + [endpos, e1l, e1r]=matching_bracket(inStr,pos); + arraystr=['[' inStr(pos:endpos)]; + arraystr=regexprep(arraystr,'"_NaN_"','NaN'); + arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf'); + arraystr(arraystr==sprintf('\n'))=[]; + arraystr(arraystr==sprintf('\r'))=[]; + %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed + if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D + astr=inStr((e1l+1):(e1r-1)); + astr=regexprep(astr,'"_NaN_"','NaN'); + astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf'); + astr(astr==sprintf('\n'))=[]; + astr(astr==sprintf('\r'))=[]; + astr(astr==' ')=''; + if(isempty(find(astr=='[', 1))) % array is 2D + dim2=length(sscanf(astr,'%f,',[1 inf])); + end + else % array is 1D + astr=arraystr(2:end-1); + astr(astr==' ')=''; + [obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]); + if(nextidx>=length(astr)-1) + object=obj; + pos=endpos; + parse_char(inStr, ']'); + return; + end + end + + try + if(~isempty(dim2)) + astr=arraystr; + astr(astr=='[')=''; + astr(astr==']')=''; + astr=regexprep(astr,'\s*$',''); + astr(astr==' ')=''; + [obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf); + if(nextidx>=length(astr)-1) + object=reshape(obj,dim2,numel(obj)/dim2)'; + pos=endpos; + parse_char(inStr, ']'); + if(pbar>0) + waitbar(pos/length(inStr),pbar,'loading ...'); + end + return; + end + end + arraystr=regexprep(arraystr,'\]\s*,','];'); + catch + end + else + arraystr='['; + end + try + arraystr=regexprep(arraystr,'^\s*\[','{','once'); + arraystr=regexprep(arraystr,'\]\s*$','}','once'); + if(isoct && regexp(arraystr,'"','once')) + error('Octave eval can produce empty cells for JSON-like input'); + end + object=eval(arraystr); + pos=endpos; + catch + while 1 + newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1); + val = parse_value(inStr, esc, newopt); + object{end+1} = val; + if next_char(inStr) == ']' + break; + end + parse_char(inStr, ','); + end + end + end + if(jsonopt('SimplifyCell',0,varargin{:})==1) + try + oldobj=object; + object=cell2mat(object')'; + if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0) + object=oldobj; + elseif(size(object,1)>1 && ismatrix(object)) + object=object'; + end + catch + end + end + parse_char(inStr, ']'); + + if(pbar>0) + waitbar(pos/length(inStr),pbar,'loading ...'); + end +%%------------------------------------------------------------------------- + +function parse_char(inStr, c) + global pos + pos=skip_whitespace(pos, inStr); + if pos > length(inStr) || inStr(pos) ~= c + error_pos(sprintf('Expected %c at position %%d', c),inStr); + else + pos = pos + 1; + pos=skip_whitespace(pos, inStr); + end + +%%------------------------------------------------------------------------- + +function c = next_char(inStr) + global pos + pos=skip_whitespace(pos, inStr); + if pos > length(inStr) + c = []; + else + c = inStr(pos); + end + +%%------------------------------------------------------------------------- + +function newpos=skip_whitespace(pos, inStr) + newpos=pos; + while newpos <= length(inStr) && isspace(inStr(newpos)) + newpos = newpos + 1; + end + +%%------------------------------------------------------------------------- +function str = parseStr(inStr, esc, varargin) + global pos index_esc + % len, ns = length(inStr), keyboard + if inStr(pos) ~= '"' + error_pos('String starting with " expected at position %d',inStr); + else + pos = pos + 1; + end + str = ''; + while pos <= length(inStr) + while index_esc <= length(esc) && esc(index_esc) < pos + index_esc = index_esc + 1; + end + if index_esc > length(esc) + str = [str inStr(pos:end)]; + pos = length(inStr) + 1; + break; + else + str = [str inStr(pos:esc(index_esc)-1)]; + pos = esc(index_esc); + end + nstr = length(str); + switch inStr(pos) + case '"' + pos = pos + 1; + if(~isempty(str)) + if(strcmp(str,'_Inf_')) + str=Inf; + elseif(strcmp(str,'-_Inf_')) + str=-Inf; + elseif(strcmp(str,'_NaN_')) + str=NaN; + end + end + return; + case '\' + if pos+1 > length(inStr) + error_pos('End of file reached right after escape character',inStr); + end + pos = pos + 1; + switch inStr(pos) + case {'"' '\' '/'} + str(nstr+1) = inStr(pos); + pos = pos + 1; + case {'b' 'f' 'n' 'r' 't'} + str(nstr+1) = sprintf(['\' inStr(pos)]); + pos = pos + 1; + case 'u' + if pos+4 > length(inStr) + error_pos('End of file reached in escaped unicode character',inStr); + end + str(nstr+(1:6)) = inStr(pos-1:pos+4); + pos = pos + 5; + end + otherwise % should never happen + str(nstr+1) = inStr(pos); + keyboard; + pos = pos + 1; + end + end + error_pos('End of file while expecting end of inStr',inStr); + +%%------------------------------------------------------------------------- + +function num = parse_number(inStr, varargin) + global pos isoct + currstr=inStr(pos:min(pos+30,end)); + if(isoct~=0) + numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end'); + [num] = sscanf(currstr, '%f', 1); + delta=numstr+1; + else + [num, one, err, delta] = sscanf(currstr, '%f', 1); + if ~isempty(err) + error_pos('Error reading number at position %d',inStr); + end + end + pos = pos + delta-1; + +%%------------------------------------------------------------------------- + +function val = parse_value(inStr, esc, varargin) + global pos + len=length(inStr); + if(isfield(varargin{1},'progressbar_')) + waitbar(pos/len,varargin{1}.progressbar_,'loading ...'); + end + + switch(inStr(pos)) + case '"' + val = parseStr(inStr, esc, varargin{:}); + return; + case '[' + val = parse_array(inStr, esc, varargin{:}); + return; + case '{' + val = parse_object(inStr, esc, varargin{:}); + return; + case {'-','0','1','2','3','4','5','6','7','8','9'} + val = parse_number(inStr, varargin{:}); + return; + case 't' + if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true') + val = true; + pos = pos + 4; + return; + end + case 'f' + if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false') + val = false; + pos = pos + 5; + return; + end + case 'n' + if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null') + val = []; + pos = pos + 4; + return; + end + end + error_pos('Value expected at position %d',inStr); +%%------------------------------------------------------------------------- + +function error_pos(msg, inStr) + global pos len + poShow = max(min([pos-15 pos-1 pos pos+20],len),1); + if poShow(3) == poShow(2) + poShow(3:4) = poShow(2)+[0 -1]; % display nothing after + end + msg = [sprintf(msg, pos) ': ' ... + inStr(poShow(1):poShow(2)) '' inStr(poShow(3):poShow(4)) ]; + error( ['JSONparser:invalidFormat: ' msg] ); + +%%------------------------------------------------------------------------- + +function str = valid_field(str) +global isoct +% From MATLAB doc: field names must begin with a letter, which may be +% followed by any combination of letters, digits, and underscores. +% Invalid characters will be converted to underscores, and the prefix +% "x0x[Hex code]_" will be added if the first character is not a letter. + pos=regexp(str,'^[^A-Za-z]','once'); + if(~isempty(pos)) + if(~isoct && str(1)+0 > 255) + str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once'); + else + str=sprintf('x0x%X_%s',char(str(1)),str(2:end)); + end + end + if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) + return; + end + if(~isoct) + str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_'); + else + pos=regexp(str,'[^0-9A-Za-z_]'); + if(isempty(pos)) + return; + end + str0=str; + pos0=[0 pos(:)' length(str)]; + str=''; + for i=1:length(pos) + str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))]; + end + if(pos(end)~=length(str)) + str=[str str0(pos0(end-1)+1:pos0(end))]; + end + end + %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_'; + +%%------------------------------------------------------------------------- +function endpos = matching_quote(str,pos) +len=length(str); +while(pos1 && str(pos-1)=='\')) + endpos=pos; + return; + end + end + pos=pos+1; +end +error('unmatched quotation mark'); +%%------------------------------------------------------------------------- +function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos) +global arraytoken +level=1; +maxlevel=level; +endpos=0; +bpos=arraytoken(arraytoken>=pos); +tokens=str(bpos); +len=length(tokens); +pos=1; +e1l=[]; +e1r=[]; +while(pos<=len) + c=tokens(pos); + if(c==']') + level=level-1; + if(isempty(e1r)) + e1r=bpos(pos); + end + if(level==0) + endpos=bpos(pos); + return + end + end + if(c=='[') + if(isempty(e1l)) + e1l=bpos(pos); + end + level=level+1; + maxlevel=max(maxlevel,level); + end + if(c=='"') + pos=matching_quote(tokens,pos+1); + end + pos=pos+1; +end +if(endpos==0) + error('unmatched "]"'); +end diff --git a/jsonlab-1.5/loadubjson.m b/jsonlab-1.5/loadubjson.m new file mode 100644 index 0000000..91e68fa --- /dev/null +++ b/jsonlab-1.5/loadubjson.m @@ -0,0 +1,457 @@ +function data = loadubjson(fname,varargin) +% +% data=loadubjson(fname,opt) +% or +% data=loadubjson(fname,'param1',value1,'param2',value2,...) +% +% parse a JSON (JavaScript Object Notation) file or string +% +% authors:Qianqian Fang (q.fang neu.edu) +% created on 2013/08/01 +% +% $Id$ +% +% input: +% fname: input file name, if fname contains "{}" or "[]", fname +% will be interpreted as a UBJSON string +% opt: a struct to store parsing options, opt can be replaced by +% a list of ('param',value) pairs - the param string is equivallent +% to a field in opt. opt can have the following +% fields (first in [.|.] is the default) +% +% opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat +% for each element of the JSON data, and group +% arrays based on the cell2mat rules. +% opt.IntEndian [B|L]: specify the endianness of the integer fields +% in the UBJSON input data. B - Big-Endian format for +% integers (as required in the UBJSON specification); +% L - input integer fields are in Little-Endian order. +% opt.NameIsString [0|1]: for UBJSON Specification Draft 8 or +% earlier versions (JSONLab 1.0 final or earlier), +% the "name" tag is treated as a string. To load +% these UBJSON data, you need to manually set this +% flag to 1. +% +% output: +% dat: a cell array, where {...} blocks are converted into cell arrays, +% and [...] are converted to arrays +% +% examples: +% obj=struct('string','value','array',[1 2 3]); +% ubjdata=saveubjson('obj',obj); +% dat=loadubjson(ubjdata) +% dat=loadubjson(['examples' filesep 'example1.ubj']) +% dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1) +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +global pos inStr len esc index_esc len_esc isoct arraytoken fileendian systemendian + +if(regexp(fname,'[\{\}\]\[]','once')) + string=fname; +elseif(exist(fname,'file')) + fid = fopen(fname,'rb'); + string = fread(fid,inf,'uint8=>char')'; + fclose(fid); +else + error('input file does not exist'); +end + +pos = 1; len = length(string); inStr = string; +isoct=exist('OCTAVE_VERSION','builtin'); +arraytoken=find(inStr=='[' | inStr==']' | inStr=='"'); +jstr=regexprep(inStr,'\\\\',' '); +escquote=regexp(jstr,'\\"'); +arraytoken=sort([arraytoken escquote]); + +% String delimiters and escape chars identified to improve speed: +esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]'); +index_esc = 1; len_esc = length(esc); + +opt=varargin2struct(varargin{:}); +fileendian=upper(jsonopt('IntEndian','B',opt)); +[os,maxelem,systemendian]=computer; + +jsoncount=1; +while pos <= len + switch(next_char) + case '{' + data{jsoncount} = parse_object(opt); + case '[' + data{jsoncount} = parse_array(opt); + otherwise + error_pos('Outer level structure must be an object or an array'); + end + jsoncount=jsoncount+1; +end % while + +jsoncount=length(data); +if(jsoncount==1 && iscell(data)) + data=data{1}; +end + +%%------------------------------------------------------------------------- +function object = parse_object(varargin) + parse_char('{'); + object = []; + type=''; + count=-1; + if(next_char == '$') + type=inStr(pos+1); % TODO + pos=pos+2; + end + if(next_char == '#') + pos=pos+1; + count=double(parse_number()); + end + if next_char ~= '}' + num=0; + while 1 + if(jsonopt('NameIsString',0,varargin{:})) + str = parseStr(varargin{:}); + else + str = parse_name(varargin{:}); + end + if isempty(str) + error_pos('Name of value at position %d cannot be empty'); + end + %parse_char(':'); + val = parse_value(varargin{:}); + num=num+1; + object.(valid_field(str))=val; + if next_char == '}' || (count>=0 && num>=count) + break; + end + %parse_char(','); + end + end + if(count==-1) + parse_char('}'); + end + if(isstruct(object)) + object=struct2jdata(object); + end + +%%------------------------------------------------------------------------- +function [cid,len]=elem_info(type) +id=strfind('iUIlLdD',type); +dataclass={'int8','uint8','int16','int32','int64','single','double'}; +bytelen=[1,1,2,4,8,4,8]; +if(id>0) + cid=dataclass{id}; + len=bytelen(id); +else + error_pos('unsupported type at position %d'); +end +%%------------------------------------------------------------------------- + + +function [data, adv]=parse_block(type,count,varargin) +global pos inStr isoct fileendian systemendian +[cid,len]=elem_info(type); +datastr=inStr(pos:pos+len*count-1); +if(isoct) + newdata=int8(datastr); +else + newdata=uint8(datastr); +end +id=strfind('iUIlLdD',type); +if(fileendian~=systemendian) + newdata=swapbytes(typecast(newdata,cid)); +end +data=typecast(newdata,cid); +adv=double(len*count); + +%%------------------------------------------------------------------------- + + +function object = parse_array(varargin) % JSON array is written in row-major order +global pos inStr + parse_char('['); + object = cell(0, 1); + dim=[]; + type=''; + count=-1; + if(next_char == '$') + type=inStr(pos+1); + pos=pos+2; + end + if(next_char == '#') + pos=pos+1; + if(next_char=='[') + dim=parse_array(varargin{:}); + count=prod(double(dim)); + else + count=double(parse_number()); + end + end + if(~isempty(type)) + if(count>=0) + [object, adv]=parse_block(type,count,varargin{:}); + if(~isempty(dim)) + object=reshape(object,dim); + end + pos=pos+adv; + return; + else + endpos=matching_bracket(inStr,pos); + [cid,len]=elem_info(type); + count=(endpos-pos)/len; + [object, adv]=parse_block(type,count,varargin{:}); + pos=pos+adv; + parse_char(']'); + return; + end + end + if next_char ~= ']' + while 1 + val = parse_value(varargin{:}); + object{end+1} = val; + if next_char == ']' + break; + end + %parse_char(','); + end + end + if(jsonopt('SimplifyCell',0,varargin{:})==1) + try + oldobj=object; + object=cell2mat(object')'; + if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0) + object=oldobj; + elseif(size(object,1)>1 && ismatrix(object)) + object=object'; + end + catch + end + end + if(count==-1) + parse_char(']'); + end + +%%------------------------------------------------------------------------- + +function parse_char(c) + global pos inStr len + skip_whitespace; + if pos > len || inStr(pos) ~= c + error_pos(sprintf('Expected %c at position %%d', c)); + else + pos = pos + 1; + skip_whitespace; + end + +%%------------------------------------------------------------------------- + +function c = next_char + global pos inStr len + skip_whitespace; + if pos > len + c = []; + else + c = inStr(pos); + end + +%%------------------------------------------------------------------------- + +function skip_whitespace + global pos inStr len + while pos <= len && isspace(inStr(pos)) + pos = pos + 1; + end + +%%------------------------------------------------------------------------- +function str = parse_name(varargin) + global pos inStr + bytelen=double(parse_number()); + if(length(inStr)>=pos+bytelen-1) + str=inStr(pos:pos+bytelen-1); + pos=pos+bytelen; + else + error_pos('End of file while expecting end of name'); + end +%%------------------------------------------------------------------------- + +function str = parseStr(varargin) + global pos inStr + % len, ns = length(inStr), keyboard + type=inStr(pos); + if type ~= 'S' && type ~= 'C' && type ~= 'H' + error_pos('String starting with S expected at position %d'); + else + pos = pos + 1; + end + if(type == 'C') + str=inStr(pos); + pos=pos+1; + return; + end + bytelen=double(parse_number()); + if(length(inStr)>=pos+bytelen-1) + str=inStr(pos:pos+bytelen-1); + pos=pos+bytelen; + else + error_pos('End of file while expecting end of inStr'); + end + +%%------------------------------------------------------------------------- + +function num = parse_number(varargin) + global pos inStr isoct fileendian systemendian + id=strfind('iUIlLdD',inStr(pos)); + if(isempty(id)) + error_pos('expecting a number at position %d'); + end + type={'int8','uint8','int16','int32','int64','single','double'}; + bytelen=[1,1,2,4,8,4,8]; + datastr=inStr(pos+1:pos+bytelen(id)); + if(isoct) + newdata=int8(datastr); + else + newdata=uint8(datastr); + end + if(fileendian~=systemendian) + newdata=swapbytes(typecast(newdata,type{id})); + end + num=typecast(newdata,type{id}); + pos = pos + bytelen(id)+1; + +%%------------------------------------------------------------------------- + +function val = parse_value(varargin) + global pos inStr + + switch(inStr(pos)) + case {'S','C','H'} + val = parseStr(varargin{:}); + return; + case '[' + val = parse_array(varargin{:}); + return; + case '{' + val = parse_object(varargin{:}); + return; + case {'i','U','I','l','L','d','D'} + val = parse_number(varargin{:}); + return; + case 'T' + val = true; + pos = pos + 1; + return; + case 'F' + val = false; + pos = pos + 1; + return; + case {'Z','N'} + val = []; + pos = pos + 1; + return; + end + error_pos('Value expected at position %d'); +%%------------------------------------------------------------------------- + +function error_pos(msg) + global pos inStr len + poShow = max(min([pos-15 pos-1 pos pos+20],len),1); + if poShow(3) == poShow(2) + poShow(3:4) = poShow(2)+[0 -1]; % display nothing after + end + msg = [sprintf(msg, pos) ': ' ... + inStr(poShow(1):poShow(2)) '' inStr(poShow(3):poShow(4)) ]; + error( ['JSONparser:invalidFormat: ' msg] ); + +%%------------------------------------------------------------------------- + +function str = valid_field(str) +global isoct +% From MATLAB doc: field names must begin with a letter, which may be +% followed by any combination of letters, digits, and underscores. +% Invalid characters will be converted to underscores, and the prefix +% "x0x[Hex code]_" will be added if the first character is not a letter. + pos=regexp(str,'^[^A-Za-z]','once'); + if(~isempty(pos)) + if(~isoct) + str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once'); + else + str=sprintf('x0x%X_%s',char(str(1)),str(2:end)); + end + end + if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) + return; + end + if(~isoct) + str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_'); + else + pos=regexp(str,'[^0-9A-Za-z_]'); + if(isempty(pos)) + return; + end + str0=str; + pos0=[0 pos(:)' length(str)]; + str=''; + for i=1:length(pos) + str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))]; + end + if(pos(end)~=length(str)) + str=[str str0(pos0(end-1)+1:pos0(end))]; + end + end + %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_'; + +%%------------------------------------------------------------------------- +function endpos = matching_quote(str,pos) +len=length(str); +while(pos1 && str(pos-1)=='\')) + endpos=pos; + return; + end + end + pos=pos+1; +end +error('unmatched quotation mark'); +%%------------------------------------------------------------------------- +function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos) +global arraytoken +level=1; +maxlevel=level; +endpos=0; +bpos=arraytoken(arraytoken>=pos); +tokens=str(bpos); +len=length(tokens); +pos=1; +e1l=[]; +e1r=[]; +while(pos<=len) + c=tokens(pos); + if(c==']') + level=level-1; + if(isempty(e1r)) + e1r=bpos(pos); + end + if(level==0) + endpos=bpos(pos); + return + end + end + if(c=='[') + if(isempty(e1l)) + e1l=bpos(pos); + end + level=level+1; + maxlevel=max(maxlevel,level); + end + if(c=='"') + pos=matching_quote(tokens,pos+1); + end + pos=pos+1; +end +if(endpos==0) + error('unmatched "]"'); +end + diff --git a/jsonlab-1.5/mergestruct.m b/jsonlab-1.5/mergestruct.m new file mode 100644 index 0000000..5448c88 --- /dev/null +++ b/jsonlab-1.5/mergestruct.m @@ -0,0 +1,33 @@ +function s=mergestruct(s1,s2) +% +% s=mergestruct(s1,s2) +% +% merge two struct objects into one +% +% authors:Qianqian Fang (q.fang neu.edu) +% date: 2012/12/22 +% +% input: +% s1,s2: a struct object, s1 and s2 can not be arrays +% +% output: +% s: the merged struct object. fields in s1 and s2 will be combined in s. +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +if(~isstruct(s1) || ~isstruct(s2)) + error('input parameters contain non-struct'); +end +if(length(s1)>1 || length(s2)>1) + error('can not merge struct arrays'); +end +fn=fieldnames(s2); +s=s1; +for i=1:length(fn) + s=setfield(s,fn{i},getfield(s2,fn{i})); +end + diff --git a/jsonlab-1.5/savejson.m b/jsonlab-1.5/savejson.m new file mode 100644 index 0000000..0583ce4 --- /dev/null +++ b/jsonlab-1.5/savejson.m @@ -0,0 +1,552 @@ +function json=savejson(rootname,obj,varargin) +% +% json=savejson(rootname,obj,filename) +% or +% json=savejson(rootname,obj,opt) +% json=savejson(rootname,obj,'param1',value1,'param2',value2,...) +% +% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript +% Object Notation) string +% +% author: Qianqian Fang (q.fang neu.edu) +% created on 2011/09/09 +% +% $Id$ +% +% input: +% rootname: the name of the root-object, when set to '', the root name +% is ignored, however, when opt.ForceRootName is set to 1 (see below), +% the MATLAB variable name will be used as the root name. +% obj: a MATLAB object (array, cell, cell array, struct, struct array, +% class instance). +% filename: a string for the file name to save the output JSON data. +% opt: a struct for additional options, ignore to use default values. +% opt can have the following fields (first in [.|.] is the default) +% +% opt.FileName [''|string]: a file name to save the output JSON data +% opt.FloatFormat ['%.10g'|string]: format to show each numeric element +% of a 1D/2D array; +% opt.ArrayIndent [1|0]: if 1, output explicit data array with +% precedent indentation; if 0, no indentation +% opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D +% array in JSON array format; if sets to 1, an +% array will be shown as a struct with fields +% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for +% sparse arrays, the non-zero elements will be +% saved to _ArrayData_ field in triplet-format i.e. +% (ix,iy,val) and "_ArrayIsSparse_" will be added +% with a value of 1; for a complex array, the +% _ArrayData_ array will include two columns +% (4 for sparse) to record the real and imaginary +% parts, and also "_ArrayIsComplex_":1 is added. +% opt.ParseLogical [0|1]: if this is set to 1, logical array elem +% will use true/false rather than 1/0. +% opt.SingletArray [0|1]: if this is set to 1, arrays with a single +% numerical element will be shown without a square +% bracket, unless it is the root object; if 0, square +% brackets are forced for any numerical arrays. +% opt.SingletCell [1|0]: if 1, always enclose a cell with "[]" +% even it has only one element; if 0, brackets +% are ignored when a cell has only 1 element. +% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson +% will use the name of the passed obj variable as the +% root object name; if obj is an expression and +% does not have a name, 'root' will be used; if this +% is set to 0 and rootname is empty, the root level +% will be merged down to the lower level. +% opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern +% to represent +/-Inf. The matched pattern is '([-+]*)Inf' +% and $1 represents the sign. For those who want to use +% 1e999 to represent Inf, they can set opt.Inf to '$11e999' +% opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern +% to represent NaN +% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding), +% for example, if opt.JSONP='foo', the JSON data is +% wrapped inside a function call as 'foo(...);' +% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson +% back to the string form +% opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode. +% opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs) +% +% opt can be replaced by a list of ('param',value) pairs. The param +% string is equivallent to a field in opt and is case sensitive. +% output: +% json: a string in the JSON format (see http://json.org) +% +% examples: +% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... +% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],... +% 'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;... +% 2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],... +% 'MeshCreator','FangQ','MeshTitle','T6 Cube',... +% 'SpecialData',[nan, inf, -inf]); +% savejson('jmesh',jsonmesh) +% savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g') +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +if(nargin==1) + varname=inputname(1); + obj=rootname; + if(isempty(varname)) + varname='root'; + end + rootname=varname; +else + varname=inputname(2); +end +if(length(varargin)==1 && ischar(varargin{1})) + opt=struct('filename',varargin{1}); +else + opt=varargin2struct(varargin{:}); +end +opt.IsOctave=exist('OCTAVE_VERSION','builtin'); +if(isfield(opt,'norowbracket')) + warning('Option ''NoRowBracket'' is depreciated, please use ''SingletArray'' and set its value to not(NoRowBracket)'); + if(~isfield(opt,'singletarray')) + opt.singletarray=not(opt.norowbracket); + end +end +rootisarray=0; +rootlevel=1; +forceroot=jsonopt('ForceRootName',0,opt); +if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || ... + iscell(obj) || isobject(obj)) && isempty(rootname) && forceroot==0) + rootisarray=1; + rootlevel=0; +else + if(isempty(rootname)) + rootname=varname; + end +end +if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot) + rootname='root'; +end + +whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')); +if(jsonopt('Compact',0,opt)==1) + whitespaces=struct('tab','','newline','','sep',','); +end +if(~isfield(opt,'whitespaces_')) + opt.whitespaces_=whitespaces; +end + +nl=whitespaces.newline; + +json=obj2json(rootname,obj,rootlevel,opt); +if(rootisarray) + json=sprintf('%s%s',json,nl); +else + json=sprintf('{%s%s%s}\n',nl,json,nl); +end + +jsonp=jsonopt('JSONP','',opt); +if(~isempty(jsonp)) + json=sprintf('%s(%s);%s',jsonp,json,nl); +end + +% save to a file if FileName is set, suggested by Patrick Rapin +filename=jsonopt('FileName','',opt); +if(~isempty(filename)) + if(jsonopt('SaveBinary',0,opt)==1) + fid = fopen(filename, 'wb'); + fwrite(fid,json); + else + fid = fopen(filename, 'wt'); + fwrite(fid,json,'char'); + end + fclose(fid); +end + +%%------------------------------------------------------------------------- +function txt=obj2json(name,item,level,varargin) + +if(iscell(item)) + txt=cell2json(name,item,level,varargin{:}); +elseif(isstruct(item)) + txt=struct2json(name,item,level,varargin{:}); +elseif(ischar(item)) + txt=str2json(name,item,level,varargin{:}); +elseif(isobject(item)) + txt=matlabobject2json(name,item,level,varargin{:}); +else + txt=mat2json(name,item,level,varargin{:}); +end + +%%------------------------------------------------------------------------- +function txt=cell2json(name,item,level,varargin) +txt={}; +if(~iscell(item)) + error('input is not a cell'); +end + +dim=size(item); +if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now + item=reshape(item,dim(1),numel(item)/dim(1)); + dim=size(item); +end +len=numel(item); +ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:}); +padding0=repmat(ws.tab,1,level); +padding2=repmat(ws.tab,1,level+1); +nl=ws.newline; +bracketlevel=~jsonopt('singletcell',1,varargin{:}); +if(len>bracketlevel) + if(~isempty(name)) + txt={padding0, '"', checkname(name,varargin{:}),'": [', nl}; name=''; + else + txt={padding0, '[', nl}; + end +elseif(len==0) + if(~isempty(name)) + txt={padding0, '"' checkname(name,varargin{:}) '": []'}; name=''; + else + txt={padding0, '[]'}; + end +end +for i=1:dim(1) + if(dim(1)>1) + txt(end+1:end+3)={padding2,'[',nl}; + end + for j=1:dim(2) + txt{end+1}=obj2json(name,item{i,j},level+(dim(1)>1)+(len>bracketlevel),varargin{:}); + if(j1) + txt(end+1:end+3)={nl,padding2,']'}; + end + if(ibracketlevel) + txt(end+1:end+3)={nl,padding0,']'}; +end +txt = sprintf('%s',txt{:}); + +%%------------------------------------------------------------------------- +function txt=struct2json(name,item,level,varargin) +txt={}; +if(~isstruct(item)) + error('input is not a struct'); +end +dim=size(item); +if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now + item=reshape(item,dim(1),numel(item)/dim(1)); + dim=size(item); +end +len=numel(item); +forcearray= (len>1 || (jsonopt('SingletArray',0,varargin{:})==1 && level>0)); +ws=struct('tab',sprintf('\t'),'newline',sprintf('\n')); +ws=jsonopt('whitespaces_',ws,varargin{:}); +padding0=repmat(ws.tab,1,level); +padding2=repmat(ws.tab,1,level+1); +padding1=repmat(ws.tab,1,level+(dim(1)>1)+forcearray); +nl=ws.newline; + +if(isempty(item)) + if(~isempty(name)) + txt={padding0, '"', checkname(name,varargin{:}),'": []'}; + else + txt={padding0, '[]'}; + end + txt = sprintf('%s',txt{:}); + return; +end +if(~isempty(name)) + if(forcearray) + txt={padding0, '"', checkname(name,varargin{:}),'": [', nl}; + end +else + if(forcearray) + txt={padding0, '[', nl}; + end +end +for j=1:dim(2) + if(dim(1)>1) + txt(end+1:end+3)={padding2,'[',nl}; + end + for i=1:dim(1) + names = fieldnames(item(i,j)); + if(~isempty(name) && len==1 && ~forcearray) + txt(end+1:end+5)={padding1, '"', checkname(name,varargin{:}),'": {', nl}; + else + txt(end+1:end+3)={padding1, '{', nl}; + end + if(~isempty(names)) + for e=1:length(names) + txt{end+1}=obj2json(names{e},item(i,j).(names{e}),... + level+(dim(1)>1)+1+forcearray,varargin{:}); + if(e1) + txt(end+1:end+3)={nl,padding2,']'}; + end + if(j1) + txt={padding1, '"', checkname(name,varargin{:}),'": [', nl}; + end +else + if(len>1) + txt={padding1, '[', nl}; + end +end +for e=1:len + val=escapejsonstring(item(e,:)); + if(len==1) + obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"']; + if(isempty(name)) + obj=['"',val,'"']; + end + txt(end+1:end+2)={padding1, obj}; + else + txt(end+1:end+4)={padding0,'"',val,'"'}; + end + if(e==len) + sep=''; + end + txt{end+1}=sep; +end +if(len>1) + txt(end+1:end+3)={nl,padding1,']'}; +end +txt = sprintf('%s',txt{:}); + +%%------------------------------------------------------------------------- +function txt=mat2json(name,item,level,varargin) +if(~isnumeric(item) && ~islogical(item)) + error('input is not an array'); +end +ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')); +ws=jsonopt('whitespaces_',ws,varargin{:}); +padding1=repmat(ws.tab,1,level); +padding0=repmat(ws.tab,1,level+1); +nl=ws.newline; +sep=ws.sep; + +if(length(size(item))>2 || issparse(item) || ~isreal(item) || ... + (isempty(item) && any(size(item))) ||jsonopt('ArrayToStruct',0,varargin{:})) + if(isempty(name)) + txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',... + padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl); + else + txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',... + padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl); + end +else + if(numel(item)==1 && jsonopt('SingletArray',0,varargin{:})==0 && level>0) + numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']',''); + else + numtxt=matdata2json(item,level+1,varargin{:}); + end + if(isempty(name)) + txt=sprintf('%s%s',padding1,numtxt); + else + if(numel(item)==1 && jsonopt('SingletArray',0,varargin{:})==0) + txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt); + else + txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt); + end + end + return; +end +dataformat='%s%s%s%s%s'; + +if(issparse(item)) + [ix,iy]=find(item); + data=full(item(find(item))); + if(~isreal(item)) + data=[real(data(:)),imag(data(:))]; + if(size(item,1)==1) + % Kludge to have data's 'transposedness' match item's. + % (Necessary for complex row vector handling below.) + data=data'; + end + txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep); + end + txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep); + if(size(item,1)==1) + % Row vector, store only column indices. + txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... + matdata2json([iy(:),data'],level+2,varargin{:}), nl); + elseif(size(item,2)==1) + % Column vector, store only row indices. + txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... + matdata2json([ix,data],level+2,varargin{:}), nl); + else + % General case, store row and column indices. + txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... + matdata2json([ix,iy,data],level+2,varargin{:}), nl); + end +else + if(isreal(item)) + txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... + matdata2json(item(:)',level+2,varargin{:}), nl); + else + txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep); + txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... + matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl); + end +end +txt=sprintf('%s%s%s',txt,padding1,'}'); + +%%------------------------------------------------------------------------- +function txt=matlabobject2json(name,item,level,varargin) +if numel(item) == 0 %empty object + st = struct(); +else + % "st = struct(item);" would produce an inmutable warning, because it + % make the protected and private properties visible. Instead we get the + % visible properties + propertynames = properties(item); + for p = 1:numel(propertynames) + for o = numel(item):-1:1 % aray of objects + st(o).(propertynames{p}) = item(o).(propertynames{p}); + end + end +end +txt=struct2json(name,st,level,varargin{:}); + +%%------------------------------------------------------------------------- +function txt=matdata2json(mat,level,varargin) + +ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')); +ws=jsonopt('whitespaces_',ws,varargin{:}); +tab=ws.tab; +nl=ws.newline; + +if(size(mat,1)==1) + pre=''; + post=''; + level=level-1; +else + pre=sprintf('[%s',nl); + post=sprintf('%s%s]',nl,repmat(tab,1,level-1)); +end + +if(isempty(mat)) + txt='null'; + return; +end +floatformat=jsonopt('FloatFormat','%.10g',varargin{:}); +%if(numel(mat)>1) + formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]]; +%else +% formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]]; +%end + +if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1) + formatstr=[repmat(tab,1,level) formatstr]; +end + +txt=sprintf(formatstr,mat'); +txt(end-length(nl):end)=[]; +if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1) + txt=regexprep(txt,'1','true'); + txt=regexprep(txt,'0','false'); +end +%txt=regexprep(mat2str(mat),'\s+',','); +%txt=regexprep(txt,';',sprintf('],\n[')); +% if(nargin>=2 && size(mat,1)>1) +% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']); +% end +txt=[pre txt post]; +if(any(isinf(mat(:)))) + txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:})); +end +if(any(isnan(mat(:)))) + txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:})); +end + +%%------------------------------------------------------------------------- +function newname=checkname(name,varargin) +isunpack=jsonopt('UnpackHex',1,varargin{:}); +newname=name; +if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once'))) + return +end +if(isunpack) + isoct=jsonopt('IsOctave',0,varargin{:}); + if(~isoct) + newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}'); + else + pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start'); + pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end'); + if(isempty(pos)) + return; + end + str0=name; + pos0=[0 pend(:)' length(name)]; + newname=''; + for i=1:length(pos) + newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))]; + end + if(pos(end)~=length(name)) + newname=[newname str0(pos0(end-1)+1:pos0(end))]; + end + end +end + +%%------------------------------------------------------------------------- +function newstr=escapejsonstring(str) +newstr=str; +isoct=exist('OCTAVE_VERSION','builtin'); +if(isoct) + vv=sscanf(OCTAVE_VERSION,'%f'); + if(vv(1)>=3.8) + isoct=0; + end +end +if(isoct) + escapechars={'\\','\"','\/','\a','\f','\n','\r','\t','\v'}; + for i=1:length(escapechars); + newstr=regexprep(newstr,escapechars{i},escapechars{i}); + end + newstr=regexprep(newstr,'\\\\(u[0-9a-fA-F]{4}[^0-9a-fA-F]*)','\$1'); +else + escapechars={'\\','\"','\/','\a','\b','\f','\n','\r','\t','\v'}; + for i=1:length(escapechars); + newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\')); + end + newstr=regexprep(newstr,'\\\\(u[0-9a-fA-F]{4}[^0-9a-fA-F]*)','\\$1'); +end diff --git a/jsonlab-1.5/saveubjson.m b/jsonlab-1.5/saveubjson.m new file mode 100644 index 0000000..66b3d2c --- /dev/null +++ b/jsonlab-1.5/saveubjson.m @@ -0,0 +1,562 @@ +function json=saveubjson(rootname,obj,varargin) +% +% json=saveubjson(rootname,obj,filename) +% or +% json=saveubjson(rootname,obj,opt) +% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...) +% +% convert a MATLAB object (cell, struct or array) into a Universal +% Binary JSON (UBJSON) binary string +% +% author: Qianqian Fang (q.fang neu.edu) +% created on 2013/08/17 +% +% $Id$ +% +% input: +% rootname: the name of the root-object, when set to '', the root name +% is ignored, however, when opt.ForceRootName is set to 1 (see below), +% the MATLAB variable name will be used as the root name. +% obj: a MATLAB object (array, cell, cell array, struct, struct array, +% class instance) +% filename: a string for the file name to save the output UBJSON data +% opt: a struct for additional options, ignore to use default values. +% opt can have the following fields (first in [.|.] is the default) +% +% opt.FileName [''|string]: a file name to save the output JSON data +% opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D +% array in JSON array format; if sets to 1, an +% array will be shown as a struct with fields +% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for +% sparse arrays, the non-zero elements will be +% saved to _ArrayData_ field in triplet-format i.e. +% (ix,iy,val) and "_ArrayIsSparse_" will be added +% with a value of 1; for a complex array, the +% _ArrayData_ array will include two columns +% (4 for sparse) to record the real and imaginary +% parts, and also "_ArrayIsComplex_":1 is added. +% opt.ParseLogical [1|0]: if this is set to 1, logical array elem +% will use true/false rather than 1/0. +% opt.SingletArray [0|1]: if this is set to 1, arrays with a single +% numerical element will be shown without a square +% bracket, unless it is the root object; if 0, square +% brackets are forced for any numerical arrays. +% opt.SingletCell [1|0]: if 1, always enclose a cell with "[]" +% even it has only one element; if 0, brackets +% are ignored when a cell has only 1 element. +% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson +% will use the name of the passed obj variable as the +% root object name; if obj is an expression and +% does not have a name, 'root' will be used; if this +% is set to 0 and rootname is empty, the root level +% will be merged down to the lower level. +% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding), +% for example, if opt.JSON='foo', the JSON data is +% wrapped inside a function call as 'foo(...);' +% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson +% back to the string form +% +% opt can be replaced by a list of ('param',value) pairs. The param +% string is equivallent to a field in opt and is case sensitive. +% output: +% json: a binary string in the UBJSON format (see http://ubjson.org) +% +% examples: +% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... +% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],... +% 'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;... +% 2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],... +% 'MeshCreator','FangQ','MeshTitle','T6 Cube',... +% 'SpecialData',[nan, inf, -inf]); +% saveubjson('jsonmesh',jsonmesh) +% saveubjson('jsonmesh',jsonmesh,'meshdata.ubj') +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +if(nargin==1) + varname=inputname(1); + obj=rootname; + if(isempty(varname)) + varname='root'; + end + rootname=varname; +else + varname=inputname(2); +end +if(length(varargin)==1 && ischar(varargin{1})) + opt=struct('filename',varargin{1}); +else + opt=varargin2struct(varargin{:}); +end +opt.IsOctave=exist('OCTAVE_VERSION','builtin'); +if(isfield(opt,'norowbracket')) + warning('Option ''NoRowBracket'' is depreciated, please use ''SingletArray'' and set its value to not(NoRowBracket)'); + if(~isfield(opt,'singletarray')) + opt.singletarray=not(opt.norowbracket); + end +end +rootisarray=0; +rootlevel=1; +forceroot=jsonopt('ForceRootName',0,opt); +if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || ... + iscell(obj) || isobject(obj)) && isempty(rootname) && forceroot==0) + rootisarray=1; + rootlevel=0; +else + if(isempty(rootname)) + rootname=varname; + end +end +if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot) + rootname='root'; +end +json=obj2ubjson(rootname,obj,rootlevel,opt); +if(~rootisarray) + json=['{' json '}']; +end + +jsonp=jsonopt('JSONP','',opt); +if(~isempty(jsonp)) + json=[jsonp '(' json ')']; +end + +% save to a file if FileName is set, suggested by Patrick Rapin +filename=jsonopt('FileName','',opt); +if(~isempty(filename)) + fid = fopen(filename, 'wb'); + fwrite(fid,json); + fclose(fid); +end + +%%------------------------------------------------------------------------- +function txt=obj2ubjson(name,item,level,varargin) + +if(iscell(item)) + txt=cell2ubjson(name,item,level,varargin{:}); +elseif(isstruct(item)) + txt=struct2ubjson(name,item,level,varargin{:}); +elseif(ischar(item)) + txt=str2ubjson(name,item,level,varargin{:}); +elseif(isobject(item)) + txt=matlabobject2ubjson(name,item,level,varargin{:}); +else + txt=mat2ubjson(name,item,level,varargin{:}); +end + +%%------------------------------------------------------------------------- +function txt=cell2ubjson(name,item,level,varargin) +txt=''; +if(~iscell(item)) + error('input is not a cell'); +end + +dim=size(item); +if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now + item=reshape(item,dim(1),numel(item)/dim(1)); + dim=size(item); +end +bracketlevel=~jsonopt('singletcell',1,varargin{:}); +len=numel(item); % let's handle 1D cell first +if(len>bracketlevel) + if(~isempty(name)) + txt=[N_(checkname(name,varargin{:})) '[']; name=''; + else + txt='['; + end +elseif(len==0) + if(~isempty(name)) + txt=[N_(checkname(name,varargin{:})) 'Z']; name=''; + else + txt='Z'; + end +end +for j=1:dim(2) + if(dim(1)>1) + txt=[txt '[']; + end + for i=1:dim(1) + txt=[txt obj2ubjson(name,item{i,j},level+(len>bracketlevel),varargin{:})]; + end + if(dim(1)>1) + txt=[txt ']']; + end +end +if(len>bracketlevel) + txt=[txt ']']; +end + +%%------------------------------------------------------------------------- +function txt=struct2ubjson(name,item,level,varargin) +txt=''; +if(~isstruct(item)) + error('input is not a struct'); +end +dim=size(item); +if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now + item=reshape(item,dim(1),numel(item)/dim(1)); + dim=size(item); +end +len=numel(item); +forcearray= (len>1 || (jsonopt('SingletArray',0,varargin{:})==1 && level>0)); + +if(~isempty(name)) + if(forcearray) + txt=[N_(checkname(name,varargin{:})) '[']; + end +else + if(forcearray) + txt='['; + end +end +for j=1:dim(2) + if(dim(1)>1) + txt=[txt '[']; + end + for i=1:dim(1) + names = fieldnames(item(i,j)); + if(~isempty(name) && len==1 && ~forcearray) + txt=[txt N_(checkname(name,varargin{:})) '{']; + else + txt=[txt '{']; + end + if(~isempty(names)) + for e=1:length(names) + txt=[txt obj2ubjson(names{e},item(i,j).(names{e}),... + level+(dim(1)>1)+1+forcearray,varargin{:})]; + end + end + txt=[txt '}']; + end + if(dim(1)>1) + txt=[txt ']']; + end +end +if(forcearray) + txt=[txt ']']; +end + +%%------------------------------------------------------------------------- +function txt=str2ubjson(name,item,level,varargin) +txt=''; +if(~ischar(item)) + error('input is not a string'); +end +item=reshape(item, max(size(item),[1 0])); +len=size(item,1); + +if(~isempty(name)) + if(len>1) + txt=[N_(checkname(name,varargin{:})) '[']; + end +else + if(len>1) + txt='['; + end +end +for e=1:len + val=item(e,:); + if(len==1) + obj=[N_(checkname(name,varargin{:})) '' '',S_(val),'']; + if(isempty(name)) + obj=['',S_(val),'']; + end + txt=[txt,'',obj]; + else + txt=[txt,'',['',S_(val),'']]; + end +end +if(len>1) + txt=[txt ']']; +end + +%%------------------------------------------------------------------------- +function txt=mat2ubjson(name,item,level,varargin) +if(~isnumeric(item) && ~islogical(item)) + error('input is not an array'); +end + +if(length(size(item))>2 || issparse(item) || ~isreal(item) || ... + (isempty(item) && any(size(item))) ||jsonopt('ArrayToStruct',0,varargin{:})) + cid=I_(uint32(max(size(item)))); + if(isempty(name)) + txt=['{' N_('_ArrayType_'),S_(class(item)),N_('_ArraySize_'),I_a(size(item),cid(1)) ]; + else + if(isempty(item)) + txt=[N_(checkname(name,varargin{:})),'Z']; + return; + else + txt=[N_(checkname(name,varargin{:})),'{',N_('_ArrayType_'),S_(class(item)),N_('_ArraySize_'),I_a(size(item),cid(1))]; + end + end +else + if(isempty(name)) + txt=matdata2ubjson(item,level+1,varargin{:}); + else + if(numel(item)==1 && jsonopt('SingletArray',0,varargin{:})==0) + numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']',''); + txt=[N_(checkname(name,varargin{:})) numtxt]; + else + txt=[N_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})]; + end + end + return; +end +if(issparse(item)) + [ix,iy]=find(item); + data=full(item(find(item))); + if(~isreal(item)) + data=[real(data(:)),imag(data(:))]; + if(size(item,1)==1) + % Kludge to have data's 'transposedness' match item's. + % (Necessary for complex row vector handling below.) + data=data'; + end + txt=[txt,N_('_ArrayIsComplex_'),'T']; + end + txt=[txt,N_('_ArrayIsSparse_'),'T']; + if(size(item,1)==1) + % Row vector, store only column indices. + txt=[txt,N_('_ArrayData_'),... + matdata2ubjson([iy(:),data'],level+2,varargin{:})]; + elseif(size(item,2)==1) + % Column vector, store only row indices. + txt=[txt,N_('_ArrayData_'),... + matdata2ubjson([ix,data],level+2,varargin{:})]; + else + % General case, store row and column indices. + txt=[txt,N_('_ArrayData_'),... + matdata2ubjson([ix,iy,data],level+2,varargin{:})]; + end +else + if(isreal(item)) + txt=[txt,N_('_ArrayData_'),... + matdata2ubjson(item(:)',level+2,varargin{:})]; + else + txt=[txt,N_('_ArrayIsComplex_'),'T']; + txt=[txt,N_('_ArrayData_'),... + matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})]; + end +end +txt=[txt,'}']; + +%%------------------------------------------------------------------------- +function txt=matlabobject2ubjson(name,item,level,varargin) +if numel(item) == 0 %empty object + st = struct(); +else + % "st = struct(item);" would produce an inmutable warning, because it + % make the protected and private properties visible. Instead we get the + % visible properties + propertynames = properties(item); + for p = 1:numel(propertynames) + for o = numel(item):-1:1 % aray of objects + st(o).(propertynames{p}) = item(o).(propertynames{p}); + end + end +end +txt=struct2ubjson(name,st,level,varargin{:}); + +%%------------------------------------------------------------------------- +function txt=matdata2ubjson(mat,level,varargin) +if(isempty(mat)) + txt='Z'; + return; +end +type=''; +hasnegtive=(mat<0); +if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0))) + if(isempty(hasnegtive)) + if(max(mat(:))<=2^8) + type='U'; + end + end + if(isempty(type)) + % todo - need to consider negative ones separately + id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]); + if(isempty(id~=0)) + error('high-precision data is not yet supported'); + end + key='iIlL'; + type=key(id~=0); + end + txt=[I_a(mat(:),type,size(mat))]; +elseif(islogical(mat)) + logicalval='FT'; + if(numel(mat)==1) + txt=logicalval(mat+1); + else + txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')]; + end +else + if(numel(mat)==1) + txt=['[' D_(mat) ']']; + else + txt=D_a(mat(:),'D',size(mat)); + end +end + +%txt=regexprep(mat2str(mat),'\s+',','); +%txt=regexprep(txt,';',sprintf('],[')); +% if(nargin>=2 && size(mat,1)>1) +% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']); +% end +if(any(isinf(mat(:)))) + txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:})); +end +if(any(isnan(mat(:)))) + txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:})); +end + +%%------------------------------------------------------------------------- +function newname=checkname(name,varargin) +isunpack=jsonopt('UnpackHex',1,varargin{:}); +newname=name; +if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once'))) + return +end +if(isunpack) + isoct=jsonopt('IsOctave',0,varargin{:}); + if(~isoct) + newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}'); + else + pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start'); + pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end'); + if(isempty(pos)) + return; + end + str0=name; + pos0=[0 pend(:)' length(name)]; + newname=''; + for i=1:length(pos) + newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))]; + end + if(pos(end)~=length(name)) + newname=[newname str0(pos0(end-1)+1:pos0(end))]; + end + end +end +%%------------------------------------------------------------------------- +function val=N_(str) +val=[I_(int32(length(str))) str]; +%%------------------------------------------------------------------------- +function val=S_(str) +if(length(str)==1) + val=['C' str]; +else + val=['S' I_(int32(length(str))) str]; +end +%%------------------------------------------------------------------------- +function val=I_(num) +if(~isinteger(num)) + error('input is not an integer'); +end +if(num>=0 && num<255) + val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')]; + return; +end +key='iIlL'; +cid={'int8','int16','int32','int64'}; +for i=1:4 + if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1))) + val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')]; + return; + end +end +error('unsupported integer'); + +%%------------------------------------------------------------------------- +function val=D_(num) +if(~isfloat(num)) + error('input is not a float'); +end + +if(isa(num,'single')) + val=['d' data2byte(swapbytes(num),'uint8')]; +else + val=['D' data2byte(swapbytes(num),'uint8')]; +end +%%------------------------------------------------------------------------- +function data=I_a(num,type,dim,format) +id=find(ismember('iUIlL',type)); + +if(id==0) + error('unsupported integer array'); +end + +% based on UBJSON specs, all integer types are stored in big endian format + +if(id==1) + data=data2byte(swapbytes(int8(num)),'uint8'); + blen=1; +elseif(id==2) + data=data2byte(swapbytes(uint8(num)),'uint8'); + blen=1; +elseif(id==3) + data=data2byte(swapbytes(int16(num)),'uint8'); + blen=2; +elseif(id==4) + data=data2byte(swapbytes(int32(num)),'uint8'); + blen=4; +elseif(id==5) + data=data2byte(swapbytes(int64(num)),'uint8'); + blen=8; +end + +if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2)) + format='opt'; +end +if((nargin<4 || strcmp(format,'opt')) && numel(num)>1) + if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2)))) + cid=I_(uint32(max(dim))); + data=['$' type '#' I_a(dim,cid(1)) data(:)']; + else + data=['$' type '#' I_(int32(numel(data)/blen)) data(:)']; + end + data=['[' data(:)']; +else + data=reshape(data,blen,numel(data)/blen); + data(2:blen+1,:)=data; + data(1,:)=type; + data=data(:)'; + data=['[' data(:)' ']']; +end +%%------------------------------------------------------------------------- +function data=D_a(num,type,dim,format) +id=find(ismember('dD',type)); + +if(id==0) + error('unsupported float array'); +end + +if(id==1) + data=data2byte(swapbytes(single(num)),'uint8'); +elseif(id==2) + data=data2byte(swapbytes(double(num)),'uint8'); +end + +if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2)) + format='opt'; +end +if((nargin<4 || strcmp(format,'opt')) && numel(num)>1) + if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2)))) + cid=I_(uint32(max(dim))); + data=['$' type '#' I_a(dim,cid(1)) data(:)']; + else + data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)']; + end + data=['[' data]; +else + data=reshape(data,(id*4),length(data)/(id*4)); + data(2:(id*4+1),:)=data; + data(1,:)=type; + data=data(:)'; + data=['[' data(:)' ']']; +end +%%------------------------------------------------------------------------- +function bytes=data2byte(varargin) +bytes=typecast(varargin{:}); +bytes=bytes(:)'; diff --git a/jsonlab-1.5/struct2jdata.m b/jsonlab-1.5/struct2jdata.m new file mode 100644 index 0000000..8980dfe --- /dev/null +++ b/jsonlab-1.5/struct2jdata.m @@ -0,0 +1,96 @@ +function newdata=struct2jdata(data,varargin) +% +% newdata=struct2jdata(data,opt,...) +% +% convert a JData object (in the form of a struct array) into an array +% +% authors:Qianqian Fang (q.fang neu.edu) +% +% input: +% data: a struct array. If data contains JData keywords in the first +% level children, these fields are parsed and regrouped into a +% data object (arrays, trees, graphs etc) based on JData +% specification. The JData keywords are +% "_ArrayType_", "_ArraySize_", "_ArrayData_" +% "_ArrayIsSparse_", "_ArrayIsComplex_" +% opt: (optional) a list of 'Param',value pairs for additional options +% The supported options include +% 'Recursive', if set to 1, will apply the conversion to +% every child; 0 to disable +% +% output: +% newdata: the covnerted data if the input data does contain a JData +% structure; otherwise, the same as the input. +% +% examples: +% obj=struct('_ArrayType_','double','_ArraySize_',[2 3], +% '_ArrayIsSparse_',1 ,'_ArrayData_',null); +% ubjdata=struct2jdata(obj); +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +fn=fieldnames(data); +newdata=data; +len=length(data); +if(jsonopt('Recursive',0,varargin{:})==1) + for i=1:length(fn) % depth-first + for j=1:len + if(isstruct(getfield(data(j),fn{i}))) + newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i}))); + end + end + end +end +if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn))) + newdata=cell(len,1); + for j=1:len + ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_); + iscpx=0; + if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn))) + if(data(j).x0x5F_ArrayIsComplex_) + iscpx=1; + end + end + if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn))) + if(data(j).x0x5F_ArrayIsSparse_) + if(~isempty(strmatch('x0x5F_ArraySize_',fn))) + dim=double(data(j).x0x5F_ArraySize_); + if(iscpx && size(ndata,2)==4-any(dim==1)) + ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end)); + end + if isempty(ndata) + % All-zeros sparse + ndata=sparse(dim(1),prod(dim(2:end))); + elseif dim(1)==1 + % Sparse row vector + ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end))); + elseif dim(2)==1 + % Sparse column vector + ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end))); + else + % Generic sparse array. + ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end))); + end + else + if(iscpx && size(ndata,2)==4) + ndata(:,3)=complex(ndata(:,3),ndata(:,4)); + end + ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3)); + end + end + elseif(~isempty(strmatch('x0x5F_ArraySize_',fn))) + if(iscpx && size(ndata,2)==2) + ndata=complex(ndata(:,1),ndata(:,2)); + end + ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_); + end + newdata{j}=ndata; + end + if(len==1) + newdata=newdata{1}; + end +end \ No newline at end of file diff --git a/jsonlab-1.5/varargin2struct.m b/jsonlab-1.5/varargin2struct.m new file mode 100644 index 0000000..9d4acf7 --- /dev/null +++ b/jsonlab-1.5/varargin2struct.m @@ -0,0 +1,40 @@ +function opt=varargin2struct(varargin) +% +% opt=varargin2struct('param1',value1,'param2',value2,...) +% or +% opt=varargin2struct(...,optstruct,...) +% +% convert a series of input parameters into a structure +% +% authors:Qianqian Fang (q.fang neu.edu) +% date: 2012/12/22 +% +% input: +% 'param', value: the input parameters should be pairs of a string and a value +% optstruct: if a parameter is a struct, the fields will be merged to the output struct +% +% output: +% opt: a struct where opt.param1=value1, opt.param2=value2 ... +% +% license: +% BSD License, see LICENSE_BSD.txt files for details +% +% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) +% + +len=length(varargin); +opt=struct; +if(len==0) return; end +i=1; +while(i<=len) + if(isstruct(varargin{i})) + opt=mergestruct(opt,varargin{i}); + elseif(ischar(varargin{i}) && i Set Path ...). + +2) Open the Simulink library browser, and look for "Real-Time Pacer" in the + list of blocksets. + +For an example model that uses these blocks, see realtime_pacer_example.mdl + +---- + diff --git a/src/RealTime_Pacer/license.txt b/src/RealTime_Pacer/license.txt new file mode 100644 index 0000000..cae4cd5 --- /dev/null +++ b/src/RealTime_Pacer/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2016, The MathWorks, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * In all cases, the software is, and all modifications and derivatives + of the software shall be, licensed to you solely for use in conjunction + with MathWorks products and service offerings. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/RealTime_Pacer/msfun_realtime_elapsed.m b/src/RealTime_Pacer/msfun_realtime_elapsed.m new file mode 100644 index 0000000..dd7747a --- /dev/null +++ b/src/RealTime_Pacer/msfun_realtime_elapsed.m @@ -0,0 +1,61 @@ +function msfun_realtime_elapsed(block) +% Help for Writing Level-2 M-File S-Functions: +% web([docroot '/toolbox/simulink/sfg/f7-67622.html'] +% http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html + +% Copyright 2009, The MathWorks, Inc. + +% instance variables +myRealTimeBaseline = 0; + +setup(block); + +%% --------------------------------------------------- + function setup(block) + % Register the number of ports. + block.NumInputPorts = 0; + block.NumOutputPorts = 1; + + block.SetPreCompOutPortInfoToDynamic; + block.OutputPort(1).Dimensions = 1; + block.OutputPort(1).SamplingMode = 'sample'; + + % Set up the states + block.NumContStates = 0; + block.NumDworks = 0; + + % Register the parameters. + block.NumDialogPrms = 0; % scale factor + + % Block is fixed in minor time step, i.e., it is only executed on major + % time steps. With a fixed-step solver, the block runs at the fastest + % discrete rate. + block.SampleTimes = [0 1]; + + block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration + + % methods called at run-time + block.RegBlockMethod('Start', @Start); + block.RegBlockMethod('Outputs', @Output); + block.RegBlockMethod('SimStatusChange', @SimStatusChange); + end + +%% + function Start(block) %#ok + myRealTimeBaseline = tic; + end + +%% + function Output(block) + block.OutputPort(1).Data = toc(myRealTimeBaseline); + end + +%% + function SimStatusChange(block, status) %#ok + if status == 1, % resume + myRealTimeBaseline = tic; + end + end + +end + diff --git a/src/RealTime_Pacer/msfun_realtime_pacer.m b/src/RealTime_Pacer/msfun_realtime_pacer.m new file mode 100644 index 0000000..1cb5675 --- /dev/null +++ b/src/RealTime_Pacer/msfun_realtime_pacer.m @@ -0,0 +1,115 @@ +function msfun_realtime_pacer(block) +% Help for Writing Level-2 M-File S-Functions: +% web([docroot '/toolbox/simulink/sfg/f7-67622.html'] +% http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html + +% Copyright 2009, The MathWorks, Inc. + +% instance variables +mySimTimePerRealTime = 1; +myRealTimeBaseline = 0; +mySimulationTimeBaseline = 0; +myResetBaseline = true; +myTotalBurnedTime = 0; +myNumUpdates = 0; + +setup(block); + +%% --------------------------------------------------- + function setup(block) + % Register the number of ports. + block.NumInputPorts = 0; + block.NumOutputPorts = 0; + + % Set up the states + block.NumContStates = 0; + block.NumDworks = 0; + + % Register the parameters. + block.NumDialogPrms = 1; % scale factor + block.DialogPrmsTunable = {'Nontunable'}; + + % Block is fixed in minor time step, i.e., it is only executed on major + % time steps. With a fixed-step solver, the block runs at the fastest + % discrete rate. + block.SampleTimes = [0 1]; + + block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration + + % methods called during update diagram/compilation. + block.RegBlockMethod('CheckParameters', @CheckPrms); + + % methods called at run-time + block.RegBlockMethod('Start', @Start); + block.RegBlockMethod('Update', @Update); + block.RegBlockMethod('SimStatusChange', @SimStatusChange); + block.RegBlockMethod('Terminate', @Terminate); + end + +%% + function CheckPrms(block) + try + validateattributes(block.DialogPrm(1).Data, {'double'},{'real', 'scalar', '>', 0}); + catch %#ok + throw(MSLException(block.BlockHandle, ... + 'Simulink:Parameters:BlkParamUndefined', ... + 'Enter a number greater than 0')); + end + end + +%% + function Start(block) + mySimTimePerRealTime = block.DialogPrm(1).Data; + myTotalBurnedTime = 0; + myNumUpdates = 0; + myResetBaseline = true; + if strcmp(pause('query'),'off') + fprintf('%s: Enabling MATLAB PAUSE command\n', getfullname(block.BlockHandle)); + pause('on'); + end + end + +%% + function Update(block) + if myResetBaseline + myRealTimeBaseline = tic; + mySimulationTimeBaseline = block.CurrentTime; + myResetBaseline = false; + else + if isinf(mySimTimePerRealTime) + return; + end + elapsedRealTime = toc(myRealTimeBaseline); + differenceInSeconds = ((block.CurrentTime - mySimulationTimeBaseline) / mySimTimePerRealTime) - elapsedRealTime; + if differenceInSeconds >= 0 + pause(differenceInSeconds); + myTotalBurnedTime = myTotalBurnedTime + differenceInSeconds; + myNumUpdates = myNumUpdates + 1; + end + end + end + +%% + function SimStatusChange(block, status) + if status == 0, + % simulation paused + fprintf('%s: Pausing real time execution of the model (simulation time = %g sec)\n', ... + getfullname(block.BlockHandle), block.CurrentTime); + elseif status == 1 + % Simulation resumed + fprintf('%s: Continuing real time execution of the model\n', ... + getfullname(block.BlockHandle)); + myResetBaseline = true; + end + end + +%% + function Terminate(block) + if myNumUpdates > 0 + fprintf('%s: Average idle real time per major time step = %g sec\n', ... + getfullname(block.BlockHandle), myTotalBurnedTime / myNumUpdates); + end + end + +end + diff --git a/src/RealTime_Pacer/realtime_pacer_example.mdl b/src/RealTime_Pacer/realtime_pacer_example.mdl new file mode 100644 index 0000000..d70a558 --- /dev/null +++ b/src/RealTime_Pacer/realtime_pacer_example.mdl @@ -0,0 +1,840 @@ +Model { + Name "realtime_pacer_example" + Version 7.5 + MdlSubVersion 0 + GraphicalInterface { + NumRootInports 0 + NumRootOutports 0 + ParameterArgumentNames "" + ComputedModelVersion "1.29" + NumModelReferences 0 + NumTestPointedSignals 0 + } + SavedCharacterEncoding "windows-1252" + SaveDefaultBlockParams on + ScopeRefreshTime 0.035000 + OverrideScopeRefreshTime on + DisableAllScopes off + DataTypeOverride "UseLocalSettings" + MinMaxOverflowLogging "UseLocalSettings" + MinMaxOverflowArchiveMode "Overwrite" + MaxMDLFileLineLength 120 + Created "Mon Oct 04 11:17:27 2010" + Creator "gvallabh" + UpdateHistory "UpdateHistoryNever" + ModifiedByFormat "%" + LastModifiedBy "gvallabh" + ModifiedDateFormat "%" + LastModifiedDate "Thu Oct 21 14:49:56 2010" + RTWModifiedTimeStamp 209573288 + ModelVersionFormat "1.%" + ConfigurationManager "None" + SampleTimeColors off + SampleTimeAnnotations off + LibraryLinkDisplay "none" + WideLines off + ShowLineDimensions off + ShowPortDataTypes off + ShowLoopsOnError on + IgnoreBidirectionalLines off + ShowStorageClass off + ShowTestPointIcons on + ShowSignalResolutionIcons on + ShowViewerIcons on + SortedOrder off + ExecutionContextIcon off + ShowLinearizationAnnotations on + BlockNameDataTip off + BlockParametersDataTip off + BlockDescriptionStringDataTip off + ToolBar on + StatusBar on + BrowserShowLibraryLinks off + BrowserLookUnderMasks off + SimulationMode "normal" + LinearizationMsg "none" + Profile off + ParamWorkspaceSource "MATLABWorkspace" + AccelSystemTargetFile "accel.tlc" + AccelTemplateMakefile "accel_default_tmf" + AccelMakeCommand "make_rtw" + TryForcingSFcnDF off + RecordCoverage off + CovPath "/" + CovSaveName "covdata" + CovMetricSettings "dw" + CovNameIncrementing off + CovHtmlReporting on + CovForceBlockReductionOff on + covSaveCumulativeToWorkspaceVar on + CovSaveSingleToWorkspaceVar on + CovCumulativeVarName "covCumulativeData" + CovCumulativeReport off + CovReportOnPause on + CovModelRefEnable "Off" + CovExternalEMLEnable off + ExtModeBatchMode off + ExtModeEnableFloating on + ExtModeTrigType "manual" + ExtModeTrigMode "normal" + ExtModeTrigPort "1" + ExtModeTrigElement "any" + ExtModeTrigDuration 1000 + ExtModeTrigDurationFloating "auto" + ExtModeTrigHoldOff 0 + ExtModeTrigDelay 0 + ExtModeTrigDirection "rising" + ExtModeTrigLevel 0 + ExtModeArchiveMode "off" + ExtModeAutoIncOneShot off + ExtModeIncDirWhenArm off + ExtModeAddSuffixToVar off + ExtModeWriteAllDataToWs off + ExtModeArmWhenConnect on + ExtModeSkipDownloadWhenConnect off + ExtModeLogAll on + ExtModeAutoUpdateStatusClock on + BufferReuse on + ShowModelReferenceBlockVersion off + ShowModelReferenceBlockIO off + Array { + Type "Handle" + Dimension 1 + Simulink.ConfigSet { + $ObjectID 1 + Version "1.10.0" + Array { + Type "Handle" + Dimension 8 + Simulink.SolverCC { + $ObjectID 2 + Version "1.10.0" + StartTime "0.0" + StopTime "5" + AbsTol "auto" + FixedStep "0.05" + InitialStep "auto" + MaxNumMinSteps "-1" + MaxOrder 5 + ZcThreshold "auto" + ConsecutiveZCsStepRelTol "10*128*eps" + MaxConsecutiveZCs "1000" + ExtrapolationOrder 4 + NumberNewtonIterations 1 + MaxStep "auto" + MinStep "auto" + MaxConsecutiveMinStep "1" + RelTol "1e-3" + SolverMode "Auto" + Solver "ode3" + SolverName "ode3" + SolverJacobianMethodControl "auto" + ShapePreserveControl "DisableAll" + ZeroCrossControl "UseLocalSettings" + ZeroCrossAlgorithm "Nonadaptive" + AlgebraicLoopSolver "TrustRegion" + SolverResetMethod "Fast" + PositivePriorityOrder off + AutoInsertRateTranBlk off + SampleTimeConstraint "Unconstrained" + InsertRTBMode "Whenever possible" + } + Simulink.DataIOCC { + $ObjectID 3 + Version "1.10.0" + Decimation "1" + ExternalInput "[t, u]" + FinalStateName "xFinal" + InitialState "xInitial" + LimitDataPoints on + MaxDataPoints "1000" + LoadExternalInput off + LoadInitialState off + SaveFinalState off + SaveCompleteFinalSimState off + SaveFormat "Array" + SaveOutput on + SaveState off + SignalLogging on + DSMLogging on + InspectSignalLogs off + SaveTime on + ReturnWorkspaceOutputs off + StateSaveName "xout" + TimeSaveName "tout" + OutputSaveName "yout" + SignalLoggingName "logsout" + DSMLoggingName "dsmout" + OutputOption "RefineOutputTimes" + OutputTimes "[]" + ReturnWorkspaceOutputsName "out" + Refine "1" + } + Simulink.OptimizationCC { + $ObjectID 4 + Version "1.10.0" + Array { + Type "Cell" + Dimension 7 + Cell "BooleansAsBitfields" + Cell "PassReuseOutputArgsAs" + Cell "PassReuseOutputArgsThreshold" + Cell "ZeroExternalMemoryAtStartup" + Cell "ZeroInternalMemoryAtStartup" + Cell "OptimizeModelRefInitCode" + Cell "NoFixptDivByZeroProtection" + PropName "DisabledProps" + } + BlockReduction on + BooleanDataType on + ConditionallyExecuteInputs on + InlineParams off + UseIntDivNetSlope off + InlineInvariantSignals off + OptimizeBlockIOStorage on + BufferReuse on + EnhancedBackFolding off + StrengthReduction off + EnforceIntegerDowncast on + ExpressionFolding on + BooleansAsBitfields off + BitfieldContainerType "uint_T" + EnableMemcpy on + MemcpyThreshold 64 + PassReuseOutputArgsAs "Structure reference" + ExpressionDepthLimit 2147483647 + FoldNonRolledExpr on + LocalBlockOutputs on + RollThreshold 5 + SystemCodeInlineAuto off + StateBitsets off + DataBitsets off + UseTempVars off + ZeroExternalMemoryAtStartup on + ZeroInternalMemoryAtStartup on + InitFltsAndDblsToZero off + NoFixptDivByZeroProtection off + EfficientFloat2IntCast off + EfficientMapNaN2IntZero on + OptimizeModelRefInitCode off + LifeSpan "inf" + MaxStackSize "Inherit from target" + BufferReusableBoundary on + SimCompilerOptimization "Off" + AccelVerboseBuild off + } + Simulink.DebuggingCC { + $ObjectID 5 + Version "1.10.0" + RTPrefix "error" + ConsistencyChecking "none" + ArrayBoundsChecking "none" + SignalInfNanChecking "none" + SignalRangeChecking "none" + ReadBeforeWriteMsg "UseLocalSettings" + WriteAfterWriteMsg "UseLocalSettings" + WriteAfterReadMsg "UseLocalSettings" + AlgebraicLoopMsg "warning" + ArtificialAlgebraicLoopMsg "warning" + SaveWithDisabledLinksMsg "warning" + SaveWithParameterizedLinksMsg "warning" + CheckSSInitialOutputMsg on + UnderspecifiedInitializationDetection "Classic" + MergeDetectMultiDrivingBlocksExec "none" + CheckExecutionContextPreStartOutputMsg off + CheckExecutionContextRuntimeOutputMsg off + SignalResolutionControl "UseLocalSettings" + BlockPriorityViolationMsg "warning" + MinStepSizeMsg "warning" + TimeAdjustmentMsg "none" + MaxConsecutiveZCsMsg "error" + SolverPrmCheckMsg "warning" + InheritedTsInSrcMsg "warning" + DiscreteInheritContinuousMsg "warning" + MultiTaskDSMMsg "error" + MultiTaskCondExecSysMsg "error" + MultiTaskRateTransMsg "error" + SingleTaskRateTransMsg "none" + TasksWithSamePriorityMsg "warning" + SigSpecEnsureSampleTimeMsg "warning" + CheckMatrixSingularityMsg "none" + IntegerOverflowMsg "warning" + Int32ToFloatConvMsg "warning" + ParameterDowncastMsg "error" + ParameterOverflowMsg "error" + ParameterUnderflowMsg "none" + ParameterPrecisionLossMsg "warning" + ParameterTunabilityLossMsg "warning" + FixptConstUnderflowMsg "none" + FixptConstOverflowMsg "none" + FixptConstPrecisionLossMsg "none" + UnderSpecifiedDataTypeMsg "none" + UnnecessaryDatatypeConvMsg "none" + VectorMatrixConversionMsg "none" + InvalidFcnCallConnMsg "error" + FcnCallInpInsideContextMsg "Use local settings" + SignalLabelMismatchMsg "none" + UnconnectedInputMsg "warning" + UnconnectedOutputMsg "warning" + UnconnectedLineMsg "warning" + SFcnCompatibilityMsg "none" + UniqueDataStoreMsg "none" + BusObjectLabelMismatch "warning" + RootOutportRequireBusObject "warning" + AssertControl "UseLocalSettings" + EnableOverflowDetection off + ModelReferenceIOMsg "none" + ModelReferenceVersionMismatchMessage "none" + ModelReferenceIOMismatchMessage "none" + ModelReferenceCSMismatchMessage "none" + UnknownTsInhSupMsg "warning" + ModelReferenceDataLoggingMessage "warning" + ModelReferenceSymbolNameMessage "warning" + ModelReferenceExtraNoncontSigs "error" + StateNameClashWarn "warning" + SimStateInterfaceChecksumMismatchMsg "warning" + StrictBusMsg "ErrorLevel1" + BusNameAdapt "WarnAndRepair" + NonBusSignalsTreatedAsBus "none" + LoggingUnavailableSignals "error" + BlockIODiagnostic "none" + } + Simulink.HardwareCC { + $ObjectID 6 + Version "1.10.0" + ProdBitPerChar 8 + ProdBitPerShort 16 + ProdBitPerInt 32 + ProdBitPerLong 32 + ProdIntDivRoundTo "Undefined" + ProdEndianess "Unspecified" + ProdWordSize 32 + ProdShiftRightIntArith on + ProdHWDeviceType "32-bit Generic" + TargetBitPerChar 8 + TargetBitPerShort 16 + TargetBitPerInt 32 + TargetBitPerLong 32 + TargetShiftRightIntArith on + TargetIntDivRoundTo "Undefined" + TargetEndianess "Unspecified" + TargetWordSize 32 + TargetTypeEmulationWarnSuppressLevel 0 + TargetPreprocMaxBitsSint 32 + TargetPreprocMaxBitsUint 32 + TargetHWDeviceType "Specified" + TargetUnknown off + ProdEqTarget on + } + Simulink.ModelReferenceCC { + $ObjectID 7 + Version "1.10.0" + UpdateModelReferenceTargets "IfOutOfDateOrStructuralChange" + CheckModelReferenceTargetMessage "error" + EnableParallelModelReferenceBuilds off + ParallelModelReferenceMATLABWorkerInit "None" + ModelReferenceNumInstancesAllowed "Multi" + PropagateVarSize "Infer from blocks in model" + ModelReferencePassRootInputsByReference on + ModelReferenceMinAlgLoopOccurrences off + PropagateSignalLabelsOutOfModel off + SupportModelReferenceSimTargetCustomCode off + } + Simulink.SFSimCC { + $ObjectID 8 + Version "1.10.0" + SFSimEnableDebug on + SFSimOverflowDetection on + SFSimEcho on + SimBlas on + SimCtrlC on + SimExtrinsic on + SimIntegrity on + SimUseLocalCustomCode off + SimBuildMode "sf_incremental_build" + } + Simulink.RTWCC { + $BackupClass "Simulink.RTWCC" + $ObjectID 9 + Version "1.10.0" + Array { + Type "Cell" + Dimension 6 + Cell "IncludeHyperlinkInReport" + Cell "GenerateTraceInfo" + Cell "GenerateTraceReport" + Cell "GenerateTraceReportSl" + Cell "GenerateTraceReportSf" + Cell "GenerateTraceReportEml" + PropName "DisabledProps" + } + SystemTargetFile "grt.tlc" + GenCodeOnly off + MakeCommand "make_rtw" + GenerateMakefile on + TemplateMakefile "grt_default_tmf" + GenerateReport off + SaveLog off + RTWVerbose on + RetainRTWFile off + ProfileTLC off + TLCDebug off + TLCCoverage off + TLCAssert off + ProcessScriptMode "Default" + ConfigurationMode "Optimized" + ConfigAtBuild off + RTWUseLocalCustomCode off + RTWUseSimCustomCode off + IncludeHyperlinkInReport off + LaunchReport off + TargetLang "C" + IncludeBusHierarchyInRTWFileBlockHierarchyMap off + IncludeERTFirstTime off + GenerateTraceInfo off + GenerateTraceReport off + GenerateTraceReportSl off + GenerateTraceReportSf off + GenerateTraceReportEml off + GenerateCodeInfo off + RTWCompilerOptimization "Off" + CheckMdlBeforeBuild "Off" + CustomRebuildMode "OnUpdate" + Array { + Type "Handle" + Dimension 2 + Simulink.CodeAppCC { + $ObjectID 10 + Version "1.10.0" + Array { + Type "Cell" + Dimension 19 + Cell "IgnoreCustomStorageClasses" + Cell "IgnoreTestpoints" + Cell "InsertBlockDesc" + Cell "SFDataObjDesc" + Cell "SimulinkDataObjDesc" + Cell "DefineNamingRule" + Cell "SignalNamingRule" + Cell "ParamNamingRule" + Cell "InlinedPrmAccess" + Cell "CustomSymbolStr" + Cell "CustomSymbolStrGlobalVar" + Cell "CustomSymbolStrType" + Cell "CustomSymbolStrField" + Cell "CustomSymbolStrFcn" + Cell "CustomSymbolStrFcnArg" + Cell "CustomSymbolStrBlkIO" + Cell "CustomSymbolStrTmpVar" + Cell "CustomSymbolStrMacro" + Cell "ReqsInCode" + PropName "DisabledProps" + } + ForceParamTrailComments off + GenerateComments on + IgnoreCustomStorageClasses on + IgnoreTestpoints off + IncHierarchyInIds off + MaxIdLength 31 + PreserveName off + PreserveNameWithParent off + ShowEliminatedStatement off + IncAutoGenComments off + SimulinkDataObjDesc off + SFDataObjDesc off + IncDataTypeInIds off + MangleLength 1 + CustomSymbolStrGlobalVar "$R$N$M" + CustomSymbolStrType "$N$R$M" + CustomSymbolStrField "$N$M" + CustomSymbolStrFcn "$R$N$M$F" + CustomSymbolStrFcnArg "rt$I$N$M" + CustomSymbolStrBlkIO "rtb_$N$M" + CustomSymbolStrTmpVar "$N$M" + CustomSymbolStrMacro "$R$N$M" + DefineNamingRule "None" + ParamNamingRule "None" + SignalNamingRule "None" + InsertBlockDesc off + SimulinkBlockComments on + EnableCustomComments off + InlinedPrmAccess "Literals" + ReqsInCode off + UseSimReservedNames off + } + Simulink.GRTTargetCC { + $BackupClass "Simulink.TargetCC" + $ObjectID 11 + Version "1.10.0" + Array { + Type "Cell" + Dimension 17 + Cell "GeneratePreprocessorConditionals" + Cell "IncludeMdlTerminateFcn" + Cell "CombineOutputUpdateFcns" + Cell "SuppressErrorStatus" + Cell "ERTCustomFileBanners" + Cell "GenerateSampleERTMain" + Cell "GenerateTestInterfaces" + Cell "ModelStepFunctionPrototypeControlCompliant" + Cell "CPPClassGenCompliant" + Cell "MultiInstanceERTCode" + Cell "PurelyIntegerCode" + Cell "SupportNonFinite" + Cell "SupportComplex" + Cell "SupportAbsoluteTime" + Cell "SupportContinuousTime" + Cell "SupportNonInlinedSFcns" + Cell "PortableWordSizes" + PropName "DisabledProps" + } + TargetFcnLib "ansi_tfl_table_tmw.mat" + TargetLibSuffix "" + TargetPreCompLibLocation "" + TargetFunctionLibrary "ANSI_C" + UtilityFuncGeneration "Auto" + ERTMultiwordTypeDef "System defined" + ERTCodeCoverageTool "None" + ERTMultiwordLength 256 + MultiwordLength 2048 + GenerateFullHeader on + GenerateSampleERTMain off + GenerateTestInterfaces off + IsPILTarget off + ModelReferenceCompliant on + ParMdlRefBuildCompliant on + CompOptLevelCompliant on + IncludeMdlTerminateFcn on + GeneratePreprocessorConditionals "Disable all" + CombineOutputUpdateFcns off + SuppressErrorStatus off + ERTFirstTimeCompliant off + IncludeFileDelimiter "Auto" + ERTCustomFileBanners off + SupportAbsoluteTime on + LogVarNameModifier "rt_" + MatFileLogging on + MultiInstanceERTCode off + SupportNonFinite on + SupportComplex on + PurelyIntegerCode off + SupportContinuousTime on + SupportNonInlinedSFcns on + SupportVariableSizeSignals off + EnableShiftOperators on + ParenthesesLevel "Nominal" + PortableWordSizes off + ModelStepFunctionPrototypeControlCompliant off + CPPClassGenCompliant off + AutosarCompliant off + UseMalloc off + ExtMode off + ExtModeStaticAlloc off + ExtModeTesting off + ExtModeStaticAllocSize 1000000 + ExtModeTransport 0 + ExtModeMexFile "ext_comm" + ExtModeIntrfLevel "Level1" + RTWCAPISignals off + RTWCAPIParams off + RTWCAPIStates off + GenerateASAP2 off + } + PropName "Components" + } + } + PropName "Components" + } + Name "Configuration" + CurrentDlgPage "Solver" + ConfigPrmDlgPosition " [ 520, 285, 1543, 940 ] " + } + PropName "ConfigurationSets" + } + Simulink.ConfigSet { + $PropName "ActiveConfigurationSet" + $ObjectID 1 + } + WSMdlFileData "DataTag0" + BlockDefaults { + ForegroundColor "black" + BackgroundColor "white" + DropShadow off + NamePlacement "normal" + FontName "Helvetica" + FontSize 10 + FontWeight "normal" + FontAngle "normal" + ShowName on + BlockRotation 0 + BlockMirror off + } + AnnotationDefaults { + HorizontalAlignment "center" + VerticalAlignment "middle" + ForegroundColor "black" + BackgroundColor "white" + DropShadow off + FontName "Helvetica" + FontSize 10 + FontWeight "normal" + FontAngle "normal" + UseDisplayTextAsClickCallback off + } + LineDefaults { + FontName "Helvetica" + FontSize 9 + FontWeight "normal" + FontAngle "normal" + } + BlockParameterDefaults { + Block { + BlockType Clock + DisplayTime off + } + Block { + BlockType Display + Format "short" + Decimation "10" + Floating off + SampleTime "-1" + } + Block { + BlockType Scope + ModelBased off + TickLabels "OneTimeTick" + ZoomMode "on" + Grid "on" + TimeRange "auto" + YMin "-5" + YMax "5" + SaveToWorkspace off + SaveName "ScopeData" + LimitDataPoints on + MaxDataPoints "5000" + Decimation "1" + SampleInput off + SampleTime "-1" + } + Block { + BlockType Sin + SineType "Time based" + TimeSource "Use simulation time" + SampleTime "-1" + VectorParams1D on + } + Block { + BlockType Sum + IconShape "rectangular" + Inputs "++" + CollapseMode "All dimensions" + CollapseDim "1" + InputSameDT on + AccumDataTypeStr "Inherit: Inherit via internal rule" + OutMin "[]" + OutMax "[]" + OutDataTypeMode "Same as first input" + OutDataType "fixdt(1,16,0)" + OutScaling "[]" + OutDataTypeStr "Inherit: Same as first input" + LockScale off + RndMeth "Floor" + SaturateOnIntegerOverflow on + SampleTime "-1" + } + } + System { + Name "realtime_pacer_example" + Location [745, 193, 1567, 855] + Open on + ModelBrowserVisibility off + ModelBrowserWidth 200 + ScreenColor "white" + PaperOrientation "landscape" + PaperPositionMode "auto" + PaperType "usletter" + PaperUnits "inches" + TiledPaperMargins [0.500000, 0.500000, 0.500000, 0.500000] + TiledPageScale 1 + ShowPageBoundaries off + ZoomFactor "100" + ReportName "simulink-default.rpt" + SIDHighWatermark 43 + Block { + BlockType Clock + Name "Clock" + SID 6 + Position [90, 245, 110, 265] + Decimation "10" + } + Block { + BlockType Display + Name "Elapsed Real Time" + SID 36 + Ports [1] + Position [275, 320, 365, 350] + Decimation "2" + Lockdown off + } + Block { + BlockType Reference + Name "Elapsed Real Time1" + SID 43 + Ports [0, 1] + Position [65, 306, 165, 364] + BackgroundColor "yellow" + ShowName off + LibraryVersion "1.9" + SourceBlock "realtime_pacer_lib/Elapsed Real Time" + SourceType "RealTime_Elapsed" + } + Block { + BlockType Display + Name "Elapsed Simulation Time" + SID 5 + Ports [1] + Position [275, 240, 365, 270] + Decimation "2" + Lockdown off + } + Block { + BlockType Reference + Name "Real-Time Pacer" + SID 30 + Ports [] + Position [65, 54, 167, 111] + BackgroundColor "yellow" + DropShadow on + ShowName off + LibraryVersion "1.9" + SourceBlock "realtime_pacer_lib/Real-Time Pacer" + SourceType "RealTime_Pacer" + simTimePerRealTime "1" + } + Block { + BlockType Scope + Name "Scope1" + SID 17 + Ports [1] + Position [295, 169, 325, 201] + Floating off + Location [188, 390, 512, 629] + Open off + NumInputPorts "1" + List { + ListType AxesTitles + axes1 "%" + } + SaveName "ScopeData1" + DataFormat "StructureWithTime" + SampleTime "0" + } + Block { + BlockType Scope + Name "Scope2" + SID 32 + Ports [1] + Position [505, 399, 535, 431] + Floating off + Location [86, 193, 679, 505] + Open off + NumInputPorts "1" + List { + ListType AxesTitles + axes1 "%" + } + YMin "-0.08" + YMax "-0.01" + DataFormat "StructureWithTime" + SampleTime "0" + } + Block { + BlockType Sin + Name "Sine Wave1" + SID 27 + Ports [0, 1] + Position [90, 170, 120, 200] + Amplitude "1" + Bias "0" + Frequency "2*pi*0.5" + Phase "0" + Samples "10" + Offset "0" + SampleTime "0" + } + Block { + BlockType Sum + Name "Subtract" + SID 42 + Ports [2, 1] + Position [245, 397, 275, 428] + Inputs "+-" + InputSameDT off + OutDataTypeMode "Inherit via internal rule" + OutDataType "fixdt(1, 16)" + OutScaling "2^-10" + OutDataTypeStr "Inherit: Inherit via internal rule" + SaturateOnIntegerOverflow off + Port { + PortNumber 1 + Name "Simulated - Real Time (seconds)" + RTWStorageClass "Auto" + DataLoggingNameMode "SignalName" + } + } + Line { + SrcBlock "Clock" + SrcPort 1 + Points [90, 0] + Branch { + DstBlock "Elapsed Simulation Time" + DstPort 1 + } + Branch { + Points [0, 150] + DstBlock "Subtract" + DstPort 1 + } + } + Line { + SrcBlock "Sine Wave1" + SrcPort 1 + DstBlock "Scope1" + DstPort 1 + } + Line { + Name "Simulated - Real Time (seconds)" + Labels [1, 1] + SrcBlock "Subtract" + SrcPort 1 + DstBlock "Scope2" + DstPort 1 + } + Line { + SrcBlock "Elapsed Real Time1" + SrcPort 1 + Points [50, 0] + Branch { + DstBlock "Elapsed Real Time" + DstPort 1 + } + Branch { + Points [0, 85] + DstBlock "Subtract" + DstPort 2 + } + } + Annotation { + Position [256, 349] + } + } +} +MatData { + NumRecords 1 + DataRecord { + Tag DataTag0 + Data " %)30 . P 8 ( @ % \" $ ! 0 % 0 !@ $ , 3F%M90" + " 5F%L=64 X P !@ @ $ 4 ( 0 , ! ! P!687( #@ #@ & \" 8" + " !0 @ ! 0 $ \"0 @ " + } +} diff --git a/src/RealTime_Pacer/realtime_pacer_help.html b/src/RealTime_Pacer/realtime_pacer_help.html new file mode 100644 index 0000000..7e343db --- /dev/null +++ b/src/RealTime_Pacer/realtime_pacer_help.html @@ -0,0 +1,40 @@ + + + +

RealTime Pacer

+

Slow down a simulation to track real (i.e., wall clock) elapsed time.

+ +

Description

+

The RealTime Pacer block slows down ("paces") simulation time to track real elapsed time. The degree of slowdown +is controllable via the Speedup parameter. To use this block, copy it anywhere in your model (it does not need +to be at the top level).

+

Some points to keep in mind when using the RealTime Pacer block:

+
    +
  1. The block relies on slowing down a simulation to make it match real time. If your model involves a lot of + computation so that 1 second of simulation time requires more than 1 second of real time, this block will not + have any effect.
  2. +
  3. The block uses the MATLAB PAUSE function to slow down the simulation. The PAUSE command gives + up the processor during the pause, so system performance does not degrade.
  4. +
  5. The matching between simulation time and elapsed real time is approximate, with expected differences on + the order of 10 to 30 milliseconds. This limitation is due to difficulties of precise timing with a multitasking + operating system.
  6. +
  7. The block does not support code generation.
  8. +
+The RealTime Pacer block works on all supported Simulink platforms. + +

Parameters

+

Speedup

+Speedup specifies the ratio between simulation time and real time. +
    +
  • Speedup can be any real value greater than zero. A value less than 1 forces the real elapsed time to be greater + than the simulation time. For example, with a speedup of 0.5, 1 second of simulation time takes 2 seconds of real time.
  • +
  • Speedup = N specifies that N seconds of simulation time correspond to one second of real time
  • +
  • Speedup = inf specifies that the simulation should run normally, at full speed
  • +
+ +

Inputs and Outputs

+None. +
+ + + diff --git a/src/RealTime_Pacer/realtime_pacer_lib.mdl.r2010a b/src/RealTime_Pacer/realtime_pacer_lib.mdl.r2010a new file mode 100644 index 0000000..086e624 --- /dev/null +++ b/src/RealTime_Pacer/realtime_pacer_lib.mdl.r2010a @@ -0,0 +1,652 @@ +Library { + Name "realtime_pacer_lib" + Version 7.5 + MdlSubVersion 0 + SavedCharacterEncoding "windows-1252" + LibraryType "BlockLibrary" + SaveDefaultBlockParams on + ScopeRefreshTime 0.035000 + OverrideScopeRefreshTime on + DisableAllScopes off + MaxMDLFileLineLength 120 + Created "Tue Oct 19 16:12:24 2010" + Creator "gvallabh" + UpdateHistory "UpdateHistoryNever" + ModifiedByFormat "%" + LastModifiedBy "gvallabh" + ModifiedDateFormat "%" + LastModifiedDate "Thu Oct 21 14:48:03 2010" + RTWModifiedTimeStamp 209573280 + ModelVersionFormat "1.%" + ConfigurationManager "None" + SampleTimeColors off + SampleTimeAnnotations off + LibraryLinkDisplay "none" + WideLines off + ShowLineDimensions off + ShowPortDataTypes off + ShowLoopsOnError on + IgnoreBidirectionalLines off + ShowStorageClass off + ShowTestPointIcons on + ShowSignalResolutionIcons on + ShowViewerIcons on + SortedOrder off + ExecutionContextIcon off + ShowLinearizationAnnotations on + BlockNameDataTip off + BlockParametersDataTip off + BlockDescriptionStringDataTip off + ToolBar on + StatusBar on + BrowserShowLibraryLinks off + BrowserLookUnderMasks off + SimulationMode "normal" + LinearizationMsg "none" + Profile off + ParamWorkspaceSource "MATLABWorkspace" + RecordCoverage off + CovSaveName "covdata" + CovMetricSettings "dw" + CovNameIncrementing off + CovHtmlReporting on + CovForceBlockReductionOff on + covSaveCumulativeToWorkspaceVar on + CovSaveSingleToWorkspaceVar on + CovCumulativeReport off + CovReportOnPause on + CovModelRefEnable "Off" + CovExternalEMLEnable off + ExtModeBatchMode off + ExtModeEnableFloating on + ExtModeTrigType "manual" + ExtModeTrigMode "normal" + ExtModeTrigPort "1" + ExtModeTrigElement "any" + ExtModeTrigDuration 1000 + ExtModeTrigDurationFloating "auto" + ExtModeTrigHoldOff 0 + ExtModeTrigDelay 0 + ExtModeTrigDirection "rising" + ExtModeTrigLevel 0 + ExtModeArchiveMode "off" + ExtModeAutoIncOneShot off + ExtModeIncDirWhenArm off + ExtModeAddSuffixToVar off + ExtModeWriteAllDataToWs off + ExtModeArmWhenConnect on + ExtModeSkipDownloadWhenConnect off + ExtModeLogAll on + ExtModeAutoUpdateStatusClock on + ShowModelReferenceBlockVersion off + ShowModelReferenceBlockIO off + Array { + Type "Handle" + Dimension 1 + Simulink.ConfigSet { + $ObjectID 1 + Version "1.10.0" + Array { + Type "Handle" + Dimension 8 + Simulink.SolverCC { + $ObjectID 2 + Version "1.10.0" + StartTime "0.0" + StopTime "10.0" + AbsTol "auto" + FixedStep "auto" + InitialStep "auto" + MaxNumMinSteps "-1" + MaxOrder 5 + ZcThreshold "auto" + ConsecutiveZCsStepRelTol "10*128*eps" + MaxConsecutiveZCs "1000" + ExtrapolationOrder 4 + NumberNewtonIterations 1 + MaxStep "auto" + MinStep "auto" + MaxConsecutiveMinStep "1" + RelTol "1e-3" + SolverMode "Auto" + Solver "ode45" + SolverName "ode45" + SolverJacobianMethodControl "auto" + ShapePreserveControl "DisableAll" + ZeroCrossControl "UseLocalSettings" + ZeroCrossAlgorithm "Nonadaptive" + AlgebraicLoopSolver "TrustRegion" + SolverResetMethod "Fast" + PositivePriorityOrder off + AutoInsertRateTranBlk off + SampleTimeConstraint "Unconstrained" + InsertRTBMode "Whenever possible" + } + Simulink.DataIOCC { + $ObjectID 3 + Version "1.10.0" + Decimation "1" + ExternalInput "[t, u]" + FinalStateName "xFinal" + InitialState "xInitial" + LimitDataPoints on + MaxDataPoints "1000" + LoadExternalInput off + LoadInitialState off + SaveFinalState off + SaveCompleteFinalSimState off + SaveFormat "Array" + SaveOutput on + SaveState off + SignalLogging on + DSMLogging on + InspectSignalLogs off + SaveTime on + ReturnWorkspaceOutputs off + StateSaveName "xout" + TimeSaveName "tout" + OutputSaveName "yout" + SignalLoggingName "logsout" + DSMLoggingName "dsmout" + OutputOption "RefineOutputTimes" + OutputTimes "[]" + ReturnWorkspaceOutputsName "out" + Refine "1" + } + Simulink.OptimizationCC { + $ObjectID 4 + Version "1.10.0" + Array { + Type "Cell" + Dimension 7 + Cell "BooleansAsBitfields" + Cell "PassReuseOutputArgsAs" + Cell "PassReuseOutputArgsThreshold" + Cell "ZeroExternalMemoryAtStartup" + Cell "ZeroInternalMemoryAtStartup" + Cell "OptimizeModelRefInitCode" + Cell "NoFixptDivByZeroProtection" + PropName "DisabledProps" + } + BlockReduction on + BooleanDataType on + ConditionallyExecuteInputs on + InlineParams off + UseIntDivNetSlope off + InlineInvariantSignals off + OptimizeBlockIOStorage on + BufferReuse on + EnhancedBackFolding off + StrengthReduction off + EnforceIntegerDowncast on + ExpressionFolding on + BooleansAsBitfields off + BitfieldContainerType "uint_T" + EnableMemcpy on + MemcpyThreshold 64 + PassReuseOutputArgsAs "Structure reference" + ExpressionDepthLimit 2147483647 + FoldNonRolledExpr on + LocalBlockOutputs on + RollThreshold 5 + SystemCodeInlineAuto off + StateBitsets off + DataBitsets off + UseTempVars off + ZeroExternalMemoryAtStartup on + ZeroInternalMemoryAtStartup on + InitFltsAndDblsToZero off + NoFixptDivByZeroProtection off + EfficientFloat2IntCast off + EfficientMapNaN2IntZero on + OptimizeModelRefInitCode off + LifeSpan "inf" + MaxStackSize "Inherit from target" + BufferReusableBoundary on + SimCompilerOptimization "Off" + AccelVerboseBuild off + } + Simulink.DebuggingCC { + $ObjectID 5 + Version "1.10.0" + RTPrefix "error" + ConsistencyChecking "none" + ArrayBoundsChecking "none" + SignalInfNanChecking "none" + SignalRangeChecking "none" + ReadBeforeWriteMsg "UseLocalSettings" + WriteAfterWriteMsg "UseLocalSettings" + WriteAfterReadMsg "UseLocalSettings" + AlgebraicLoopMsg "warning" + ArtificialAlgebraicLoopMsg "warning" + SaveWithDisabledLinksMsg "warning" + SaveWithParameterizedLinksMsg "warning" + CheckSSInitialOutputMsg on + UnderspecifiedInitializationDetection "Classic" + MergeDetectMultiDrivingBlocksExec "none" + CheckExecutionContextPreStartOutputMsg off + CheckExecutionContextRuntimeOutputMsg off + SignalResolutionControl "UseLocalSettings" + BlockPriorityViolationMsg "warning" + MinStepSizeMsg "warning" + TimeAdjustmentMsg "none" + MaxConsecutiveZCsMsg "error" + SolverPrmCheckMsg "warning" + InheritedTsInSrcMsg "warning" + DiscreteInheritContinuousMsg "warning" + MultiTaskDSMMsg "error" + MultiTaskCondExecSysMsg "error" + MultiTaskRateTransMsg "error" + SingleTaskRateTransMsg "none" + TasksWithSamePriorityMsg "warning" + SigSpecEnsureSampleTimeMsg "warning" + CheckMatrixSingularityMsg "none" + IntegerOverflowMsg "warning" + Int32ToFloatConvMsg "warning" + ParameterDowncastMsg "error" + ParameterOverflowMsg "error" + ParameterUnderflowMsg "none" + ParameterPrecisionLossMsg "warning" + ParameterTunabilityLossMsg "warning" + FixptConstUnderflowMsg "none" + FixptConstOverflowMsg "none" + FixptConstPrecisionLossMsg "none" + UnderSpecifiedDataTypeMsg "none" + UnnecessaryDatatypeConvMsg "none" + VectorMatrixConversionMsg "none" + InvalidFcnCallConnMsg "error" + FcnCallInpInsideContextMsg "Use local settings" + SignalLabelMismatchMsg "none" + UnconnectedInputMsg "warning" + UnconnectedOutputMsg "warning" + UnconnectedLineMsg "warning" + SFcnCompatibilityMsg "none" + UniqueDataStoreMsg "none" + BusObjectLabelMismatch "warning" + RootOutportRequireBusObject "warning" + AssertControl "UseLocalSettings" + EnableOverflowDetection off + ModelReferenceIOMsg "none" + ModelReferenceVersionMismatchMessage "none" + ModelReferenceIOMismatchMessage "none" + ModelReferenceCSMismatchMessage "none" + UnknownTsInhSupMsg "warning" + ModelReferenceDataLoggingMessage "warning" + ModelReferenceSymbolNameMessage "warning" + ModelReferenceExtraNoncontSigs "error" + StateNameClashWarn "warning" + SimStateInterfaceChecksumMismatchMsg "warning" + StrictBusMsg "ErrorLevel1" + BusNameAdapt "WarnAndRepair" + NonBusSignalsTreatedAsBus "none" + LoggingUnavailableSignals "error" + BlockIODiagnostic "none" + } + Simulink.HardwareCC { + $ObjectID 6 + Version "1.10.0" + ProdBitPerChar 8 + ProdBitPerShort 16 + ProdBitPerInt 32 + ProdBitPerLong 32 + ProdIntDivRoundTo "Undefined" + ProdEndianess "Unspecified" + ProdWordSize 32 + ProdShiftRightIntArith on + ProdHWDeviceType "32-bit Generic" + TargetBitPerChar 8 + TargetBitPerShort 16 + TargetBitPerInt 32 + TargetBitPerLong 32 + TargetShiftRightIntArith on + TargetIntDivRoundTo "Undefined" + TargetEndianess "Unspecified" + TargetWordSize 32 + TargetTypeEmulationWarnSuppressLevel 0 + TargetPreprocMaxBitsSint 32 + TargetPreprocMaxBitsUint 32 + TargetHWDeviceType "Specified" + TargetUnknown off + ProdEqTarget on + } + Simulink.ModelReferenceCC { + $ObjectID 7 + Version "1.10.0" + UpdateModelReferenceTargets "IfOutOfDateOrStructuralChange" + CheckModelReferenceTargetMessage "error" + EnableParallelModelReferenceBuilds off + ParallelModelReferenceMATLABWorkerInit "None" + ModelReferenceNumInstancesAllowed "Multi" + PropagateVarSize "Infer from blocks in model" + ModelReferencePassRootInputsByReference on + ModelReferenceMinAlgLoopOccurrences off + PropagateSignalLabelsOutOfModel off + SupportModelReferenceSimTargetCustomCode off + } + Simulink.SFSimCC { + $ObjectID 8 + Version "1.10.0" + SFSimEnableDebug on + SFSimOverflowDetection on + SFSimEcho on + SimBlas on + SimCtrlC on + SimExtrinsic on + SimIntegrity on + SimUseLocalCustomCode off + SimBuildMode "sf_incremental_build" + } + Simulink.RTWCC { + $BackupClass "Simulink.RTWCC" + $ObjectID 9 + Version "1.10.0" + Array { + Type "Cell" + Dimension 6 + Cell "IncludeHyperlinkInReport" + Cell "GenerateTraceInfo" + Cell "GenerateTraceReport" + Cell "GenerateTraceReportSl" + Cell "GenerateTraceReportSf" + Cell "GenerateTraceReportEml" + PropName "DisabledProps" + } + SystemTargetFile "grt.tlc" + GenCodeOnly off + MakeCommand "make_rtw" + GenerateMakefile on + TemplateMakefile "grt_default_tmf" + GenerateReport off + SaveLog off + RTWVerbose on + RetainRTWFile off + ProfileTLC off + TLCDebug off + TLCCoverage off + TLCAssert off + ProcessScriptMode "Default" + ConfigurationMode "Optimized" + ConfigAtBuild off + RTWUseLocalCustomCode off + RTWUseSimCustomCode off + IncludeHyperlinkInReport off + LaunchReport off + TargetLang "C" + IncludeBusHierarchyInRTWFileBlockHierarchyMap off + IncludeERTFirstTime off + GenerateTraceInfo off + GenerateTraceReport off + GenerateTraceReportSl off + GenerateTraceReportSf off + GenerateTraceReportEml off + GenerateCodeInfo off + RTWCompilerOptimization "Off" + CheckMdlBeforeBuild "Off" + CustomRebuildMode "OnUpdate" + Array { + Type "Handle" + Dimension 2 + Simulink.CodeAppCC { + $ObjectID 10 + Version "1.10.0" + Array { + Type "Cell" + Dimension 19 + Cell "IgnoreCustomStorageClasses" + Cell "IgnoreTestpoints" + Cell "InsertBlockDesc" + Cell "SFDataObjDesc" + Cell "SimulinkDataObjDesc" + Cell "DefineNamingRule" + Cell "SignalNamingRule" + Cell "ParamNamingRule" + Cell "InlinedPrmAccess" + Cell "CustomSymbolStr" + Cell "CustomSymbolStrGlobalVar" + Cell "CustomSymbolStrType" + Cell "CustomSymbolStrField" + Cell "CustomSymbolStrFcn" + Cell "CustomSymbolStrFcnArg" + Cell "CustomSymbolStrBlkIO" + Cell "CustomSymbolStrTmpVar" + Cell "CustomSymbolStrMacro" + Cell "ReqsInCode" + PropName "DisabledProps" + } + ForceParamTrailComments off + GenerateComments on + IgnoreCustomStorageClasses on + IgnoreTestpoints off + IncHierarchyInIds off + MaxIdLength 31 + PreserveName off + PreserveNameWithParent off + ShowEliminatedStatement off + IncAutoGenComments off + SimulinkDataObjDesc off + SFDataObjDesc off + IncDataTypeInIds off + MangleLength 1 + CustomSymbolStrGlobalVar "$R$N$M" + CustomSymbolStrType "$N$R$M" + CustomSymbolStrField "$N$M" + CustomSymbolStrFcn "$R$N$M$F" + CustomSymbolStrFcnArg "rt$I$N$M" + CustomSymbolStrBlkIO "rtb_$N$M" + CustomSymbolStrTmpVar "$N$M" + CustomSymbolStrMacro "$R$N$M" + DefineNamingRule "None" + ParamNamingRule "None" + SignalNamingRule "None" + InsertBlockDesc off + SimulinkBlockComments on + EnableCustomComments off + InlinedPrmAccess "Literals" + ReqsInCode off + UseSimReservedNames off + } + Simulink.GRTTargetCC { + $BackupClass "Simulink.TargetCC" + $ObjectID 11 + Version "1.10.0" + Array { + Type "Cell" + Dimension 17 + Cell "GeneratePreprocessorConditionals" + Cell "IncludeMdlTerminateFcn" + Cell "CombineOutputUpdateFcns" + Cell "SuppressErrorStatus" + Cell "ERTCustomFileBanners" + Cell "GenerateSampleERTMain" + Cell "GenerateTestInterfaces" + Cell "ModelStepFunctionPrototypeControlCompliant" + Cell "CPPClassGenCompliant" + Cell "MultiInstanceERTCode" + Cell "PurelyIntegerCode" + Cell "SupportNonFinite" + Cell "SupportComplex" + Cell "SupportAbsoluteTime" + Cell "SupportContinuousTime" + Cell "SupportNonInlinedSFcns" + Cell "PortableWordSizes" + PropName "DisabledProps" + } + TargetFcnLib "ansi_tfl_table_tmw.mat" + TargetLibSuffix "" + TargetPreCompLibLocation "" + TargetFunctionLibrary "ANSI_C" + UtilityFuncGeneration "Auto" + ERTMultiwordTypeDef "System defined" + ERTCodeCoverageTool "None" + ERTMultiwordLength 256 + MultiwordLength 2048 + GenerateFullHeader on + GenerateSampleERTMain off + GenerateTestInterfaces off + IsPILTarget off + ModelReferenceCompliant on + ParMdlRefBuildCompliant on + CompOptLevelCompliant on + IncludeMdlTerminateFcn on + GeneratePreprocessorConditionals "Disable all" + CombineOutputUpdateFcns off + SuppressErrorStatus off + ERTFirstTimeCompliant off + IncludeFileDelimiter "Auto" + ERTCustomFileBanners off + SupportAbsoluteTime on + LogVarNameModifier "rt_" + MatFileLogging on + MultiInstanceERTCode off + SupportNonFinite on + SupportComplex on + PurelyIntegerCode off + SupportContinuousTime on + SupportNonInlinedSFcns on + SupportVariableSizeSignals off + EnableShiftOperators on + ParenthesesLevel "Nominal" + PortableWordSizes off + ModelStepFunctionPrototypeControlCompliant off + CPPClassGenCompliant off + AutosarCompliant off + UseMalloc off + ExtMode off + ExtModeStaticAlloc off + ExtModeTesting off + ExtModeStaticAllocSize 1000000 + ExtModeTransport 0 + ExtModeMexFile "ext_comm" + ExtModeIntrfLevel "Level1" + RTWCAPISignals off + RTWCAPIParams off + RTWCAPIStates off + GenerateASAP2 off + } + PropName "Components" + } + } + PropName "Components" + } + Name "Configuration" + CurrentDlgPage "Solver" + ConfigPrmDlgPosition " [ 520, 285, 1400, 915 ] " + } + PropName "ConfigurationSets" + } + BlockDefaults { + ForegroundColor "black" + BackgroundColor "white" + DropShadow off + NamePlacement "normal" + FontName "Helvetica" + FontSize 10 + FontWeight "normal" + FontAngle "normal" + ShowName on + BlockRotation 0 + BlockMirror off + } + AnnotationDefaults { + HorizontalAlignment "center" + VerticalAlignment "middle" + ForegroundColor "black" + BackgroundColor "white" + DropShadow off + FontName "Helvetica" + FontSize 10 + FontWeight "normal" + FontAngle "normal" + UseDisplayTextAsClickCallback off + } + LineDefaults { + FontName "Helvetica" + FontSize 9 + FontWeight "normal" + FontAngle "normal" + } + BlockParameterDefaults { + Block { + BlockType "M-S-Function" + FunctionName "mlfile" + DisplayMFileStacktrace on + } + } + System { + Name "realtime_pacer_lib" + Location [222, 287, 618, 534] + Open on + ModelBrowserVisibility off + ModelBrowserWidth 200 + ScreenColor "white" + PaperOrientation "landscape" + PaperPositionMode "auto" + PaperType "usletter" + PaperUnits "inches" + TiledPaperMargins [0.500000, 0.500000, 0.500000, 0.500000] + TiledPageScale 1 + ShowPageBoundaries off + ZoomFactor "100" + ReportName "simulink-default.rpt" + SIDHighWatermark 3 + Block { + BlockType "M-S-Function" + Name "Elapsed Real Time" + SID 3 + Ports [0, 1] + Position [200, 81, 300, 139] + BackgroundColor "yellow" + ShowName off + FunctionName "msfun_realtime_elapsed" + MaskType "RealTime_Elapsed" + MaskDescription "Output the elapsed real (wall clock) time in seconds since the start or most recent conti" + "nuation of the simulation.\n\nThe accuracy of the elapsed time calculation is limited by the timing-related jitt" + "er in a multitasking operating system (typically between 10 and 30 milliseconds)." + MaskDisplay "disp('Elapsed Real Time')" + MaskIconFrame on + MaskIconOpaque on + MaskIconRotate "none" + MaskPortRotate "default" + MaskIconUnits "normalized" + } + Block { + BlockType "M-S-Function" + Name "Real-Time Pacer" + SID 2 + Ports [] + Position [50, 79, 152, 136] + BackgroundColor "yellow" + DropShadow on + ShowName off + FunctionName "msfun_realtime_pacer" + Parameters "simTimePerRealTime" + MaskType "RealTime_Pacer" + MaskDescription "Slow down a simulation to track real (i.e., wall clock) elapsed time. \n\n\"Speedup\" spe" + "cifies the ratio between simulation time and real time \n• Speedup = N => N sec. of simulation time per sec. of " + "real time\n• Speedup can be fractional (e.g., 0.5, 1.3). \n• Speedup = inf => allow simulation to run at full sp" + "eed\n\nClick on the Help button for details.\n " + MaskHelp "web('realtime_pacer_help.html', '-helpbrowser')" + MaskPromptString "Speedup (Simulation Time / Real Time):" + MaskStyleString "edit" + MaskTunableValueString "on" + MaskEnableString "on" + MaskVisibilityString "on" + MaskToolTipString "on" + MaskVariables "simTimePerRealTime=@1;" + MaskDisplay "fprintf('Real-Time Pacer\\nSpeedup = %g', simTimePerRealTime)" + MaskIconFrame on + MaskIconOpaque on + MaskIconRotate "none" + MaskPortRotate "default" + MaskIconUnits "normalized" + MaskValueString "1" + } + Annotation { + Name "Real-Time Pacer Library" + Position [183, 36] + FontName "Arial" + FontSize 12 + FontWeight "bold" + } + } +} diff --git a/src/RealTime_Pacer/realtime_pacer_lib.slx b/src/RealTime_Pacer/realtime_pacer_lib.slx new file mode 100644 index 0000000..bae0b58 Binary files /dev/null and b/src/RealTime_Pacer/realtime_pacer_lib.slx differ diff --git a/src/RealTime_Pacer/slblocks.m b/src/RealTime_Pacer/slblocks.m new file mode 100644 index 0000000..61f2fba --- /dev/null +++ b/src/RealTime_Pacer/slblocks.m @@ -0,0 +1,5 @@ +function blkStruct = slblocks + +blkStruct.Name = 'Real-Time Pacer'; +blkStruct.OpenFcn = 'realtime_pacer_lib'; +blkStruct.MaskInitialization = ''; diff --git a/src/at.m b/src/at.m new file mode 100644 index 0000000..dc2d3e3 --- /dev/null +++ b/src/at.m @@ -0,0 +1,16 @@ +%at(x, ...) returns a circular access on x, by ... +%example: x = [1 2; 3 4]; at(x, 3, 4) == 2 + +function got = at(x, varargin) + idx = varargin; + for k = 1:length(idx) + if idx{k} ~= ':' + idx{k} = mod(idx{k} - 1, size(x, k)) + 1; + end + end + if ~isempty(x) + got = x(idx{:}); + else + got = 0; + end +end \ No newline at end of file diff --git a/src/clickableLegend.m b/src/clickableLegend.m new file mode 100644 index 0000000..1dd5dc1 --- /dev/null +++ b/src/clickableLegend.m @@ -0,0 +1,200 @@ +function varargout = clickableLegend(varargin) +% clickableLegend Interactive legend for toggling or highlighting graphics +% +% clickableLegend is a wrapper around the LEGEND function that provides +% interactive display toggling or highlighting of lines or patches in a MATLAB +% plot. It enables you to, +% * Toggle (hide/show) a graphics object (or group) by clicking on an +% associated text label in the legend +% * Highlight and identify a graphics object (or group) by clicking it. +% +% Its usage is the same as the LEGEND function with additional +% optional parameters. For further information please see the LEGEND documentation. +% +% ADDITIONAL ARGUMENTS specific to clickableLegend: +% These are passed in as parameter-value pairs +% +% * groups: A vector specifying the group membership for every line object. +% The grouping parameter lets you have a group of lines represented and +% controlled by one entry in the legend. This can be useful if you would +% like to highlight or hide a group of lines by clicking on one legend entry. +% CONSIDERATIONS: +% # The number of unique entries in the group vector must match the +% number of strings in the legend +% # When passing a vector of line/patch handles as the first input +% argument, the vector should contain all lines/patches whose group +% membership is included in the group vector. ie. the length of the +% vector of handles must match that of the length of the group vector. +% +% * displayedLines: A vector of indices corresponding to the lines or groups that +% should be displayed initially. This option is useful if there are too +% many lines in the figure and you are only interested in looking at a +% few at first. +% Example: clickableLegend(..., 'displayedLines', [4 5 6]) +% +% * plotOptions: A cell array of parameter value pairs that define +% properties of the graphics objects in the legend. This can be useful, +% for example, to ensure consistent marker sizes within the legend. +% +% Notes: +% 1. If you save the figure and re-load it, the toggling functionality +% is not automatically re-enabled. To restore it, simply call clickableLegend +% with no arguments. +% +% 2. To prevent the axis from automatically scaling every time a line is +% turned on and off, issue the command: axis manual +% +% Example 1: +% z = peaks(100); +% plot(z(:,26:5:50)) +% grid on; +% axis manual; +% clickableLegend({'Line1','Line2','Line3','Line4','Line5'}, 'Location', 'NorthWest'); +% +% Example 2: +% f = plot([1:10;1:2:20]','x'); hold on; +% g = plot(sin([1:10;1:2:20]'),'r-'); +% h = plot(11:20,rand(5,10)*5,'b:'); +% clickableLegend([f;g;h], {'Line1','Line2','Line3'},... +% 'groups', [1 1 2 2 3 3 3 3 3], 'displayedLines', [2 3]); +% +% hgsave(gcf, 'testfig.fig'); +% hgload testfig.fig +% clickableLegend +% +% See also legend, clickableLegend_examples + +% Copyright 2009-2014 MathWorks, Inc. + +% Extract any arguments for clickableLegend +[dispinds, groupmem, plotOptions, varargin] = ... + extractOptionalArgs(varargin{:}); + +% Process group memberships +[groups, plotObj, varargin] = processGroups(groupmem, varargin{:}); + +% Create legend +[varargout{1:nargout(@legend)}] = legend(varargin{:}); + +% Extract what is needed for the rest of the function and fix varargout +[leghan, objhan, plothan] = varargout{1:3}; +% objhan: strings +% plothan: graphics objects +varargout = varargout(1:nargout); + +if isempty(groupmem) % Default group membership + groupmem = 1:length(plothan); + plotObj = plothan; + groups = groupmem; +end + +if ~isempty(dispinds) % DisplayedLines parameter was specified + hidden = true(1, length(plothan)); + dispinds(dispinds>length(plothan)) = []; + hidden(dispinds) = false; +end + +% Set the callbacks & plot options +for i = 1:length(plothan) + set(objhan(i), 'HitTest', 'on', 'ButtonDownFcn',... + @(varargin)togglevisibility(objhan(i),plotObj(groupmem==groups(i))),... + 'UserData', true); + if ~isempty(dispinds) && hidden(i) + togglevisibility(objhan(i), plotObj(groupmem==groups(i))); + end + set(plotObj(groupmem==groups(i)), 'HitTest', 'on', 'ButtonDownFcn', ... + @(varargin)highlightObject(objhan(i),plothan(i),... + plotObj(groupmem==groups(i)),plotOptions),... + 'UserData', false); + if ~isempty(plotOptions) + set(plothan(i), plotOptions{:}); + end +end + + +function togglevisibility(hObject, obj) +if get(hObject, 'UserData') % It is on, turn it off + set(hObject, 'Color', (get(hObject, 'Color') + 1)/1.5, 'UserData', false); + set(obj,'HitTest','off','Visible','off','handlevisibility','off'); +else + set(hObject, 'Color', get(hObject, 'Color')*1.5 - 1, 'UserData', true); + set(obj, 'HitTest','on','visible','on','handlevisibility','on'); +end + +function highlightObject(lTextObj, lMarkerObj, plotObj, plotOptions) +lw = get(plotObj,'LineWidth'); +if ~iscell(lw), lw = {lw}; end; +ms = get(plotObj,'MarkerSize'); +if ~iscell(ms), ms = {ms}; end; + +if ~get(plotObj(1), 'UserData') % It is not selected, highlight it + %set(hObject, 'FontWeight', 'bold'); + set(lTextObj, 'EdgeColor', 'k'); + set(plotObj, {'LineWidth', 'MarkerSize'}, [cellfun(@(x)x+2, lw, 'Uniformoutput', false) cellfun(@(x)x+2, ms, 'uniformoutput', false)]); + set(plotObj, 'UserData', true); +else + %set(hObject, 'FontWeight', 'normal'); + set(lTextObj, 'EdgeColor', 'none'); + set(plotObj, {'LineWidth', 'MarkerSize'}, [cellfun(@(x)x-2, lw, 'Uniformoutput', false) cellfun(@(x)x-2, ms, 'uniformoutput', false)]); + set(plotObj, 'UserData', false); +end +if ~isempty(plotOptions) + set(lMarkerObj, plotOptions{:}); +end + +function [dispinds, groupmem, plotOpt, varargin] = extractOptionalArgs(varargin) +% Extract the displayedlines and/or groups arguments if specified + +ind = find(strcmpi(varargin,'DisplayedLines')); +if ~isempty(ind) + assert(ind 1 && ishandle(varargin{1}(1)) + if strcmpi(get(varargin{1}(1),'Type'),'axes') + hAxes = varargin{1}(1); + obj = flipud([findobj(hAxes,'Type','line');findobj(hAxes,'Type','patch')]); + else % It's a line/patch + obj = varargin{1}; + [~,firstmem] = ismember(groups, groupmem); + %for i = 1:length(groups) + % firstmem(i) = find(groupmem==groups(i),1); + %end + varargin{1} = obj(firstmem); + end +else + hAxes = gca; + obj = flipud([findobj(hAxes,'Type','line');findobj(hAxes,'Type','patch')]); +end \ No newline at end of file diff --git a/src/convp.m b/src/convp.m new file mode 100644 index 0000000..e8ccc89 --- /dev/null +++ b/src/convp.m @@ -0,0 +1,14 @@ +%iterates the convolution n times on poly (power of n) +%y = convp(x, n) +%Ex: conv(conv(x, x), x) == convp(x, 3) +function y = convp(x, n) + assert(n >= 0, 'convp n must be >= 0'); + if n == 0 + y = 1; + else + y = x; + end + for i = 2:n + y = conv(y, x); + end +end \ No newline at end of file diff --git a/src/inpaint_nans.m b/src/inpaint_nans.m new file mode 100644 index 0000000..2460b51 --- /dev/null +++ b/src/inpaint_nans.m @@ -0,0 +1 @@ +function B=inpaint_nans(A,method) % INPAINT_NANS: in-paints over nans in an array % usage: B=INPAINT_NANS(A) % default method % usage: B=INPAINT_NANS(A,method) % specify method used % % Solves approximation to one of several pdes to % interpolate and extrapolate holes in an array % % arguments (input): % A - nxm array with some NaNs to be filled in % % method - (OPTIONAL) scalar numeric flag - specifies % which approach (or physical metaphor to use % for the interpolation.) All methods are capable % of extrapolation, some are better than others. % There are also speed differences, as well as % accuracy differences for smooth surfaces. % % methods {0,1,2} use a simple plate metaphor. % method 3 uses a better plate equation, % but may be much slower and uses % more memory. % method 4 uses a spring metaphor. % method 5 is an 8 neighbor average, with no % rationale behind it compared to the % other methods. I do not recommend % its use. % % method == 0 --> (DEFAULT) see method 1, but % this method does not build as large of a % linear system in the case of only a few % NaNs in a large array. % Extrapolation behavior is linear. % % method == 1 --> simple approach, applies del^2 % over the entire array, then drops those parts % of the array which do not have any contact with % NaNs. Uses a least squares approach, but it % does not modify known values. % In the case of small arrays, this method is % quite fast as it does very little extra work. % Extrapolation behavior is linear. % % method == 2 --> uses del^2, but solving a direct % linear system of equations for nan elements. % This method will be the fastest possible for % large systems since it uses the sparsest % possible system of equations. Not a least % squares approach, so it may be least robust % to noise on the boundaries of any holes. % This method will also be least able to % interpolate accurately for smooth surfaces. % Extrapolation behavior is linear. % % Note: method 2 has problems in 1-d, so this % method is disabled for vector inputs. % % method == 3 --+ See method 0, but uses del^4 for % the interpolating operator. This may result % in more accurate interpolations, at some cost % in speed. % % method == 4 --+ Uses a spring metaphor. Assumes % springs (with a nominal length of zero) % connect each node with every neighbor % (horizontally, vertically and diagonally) % Since each node tries to be like its neighbors, % extrapolation is as a constant function where % this is consistent with the neighboring nodes. % % method == 5 --+ See method 2, but use an average % of the 8 nearest neighbors to any element. % This method is NOT recommended for use. % % % arguments (output): % B - nxm array with NaNs replaced % % % Example: % [x,y] = meshgrid(0:.01:1); % z0 = exp(x+y); % znan = z0; % znan(20:50,40:70) = NaN; % znan(30:90,5:10) = NaN; % znan(70:75,40:90) = NaN; % % z = inpaint_nans(znan); % % % See also: griddata, interp1 % % Author: John D'Errico % e-mail address: woodchips@rochester.rr.com % Release: 2 % Release date: 4/15/06 % I always need to know which elements are NaN, % and what size the array is for any method [n,m]=size(A); A=A(:); nm=n*m; k=isnan(A(:)); % list the nodes which are known, and which will % be interpolated nan_list=find(k); known_list=find(~k); % how many nans overall nan_count=length(nan_list); % convert NaN indices to (r,c) form % nan_list==find(k) are the unrolled (linear) indices % (row,column) form [nr,nc]=ind2sub([n,m],nan_list); % both forms of index in one array: % column 1 == unrolled index % column 2 == row index % column 3 == column index nan_list=[nan_list,nr,nc]; % supply default method if (nargin<2) || isempty(method) method = 0; elseif ~ismember(method,0:5) error 'If supplied, method must be one of: {0,1,2,3,4,5}.' end % for different methods switch method case 0 % The same as method == 1, except only work on those % elements which are NaN, or at least touch a NaN. % is it 1-d or 2-d? if (m == 1) || (n == 1) % really a 1-d case work_list = nan_list(:,1); work_list = unique([work_list;work_list - 1;work_list + 1]); work_list(work_list <= 1) = []; work_list(work_list >= nm) = []; nw = numel(work_list); u = (1:nw)'; fda = sparse(repmat(u,1,3),bsxfun(@plus,work_list,-1:1), ... repmat([1 -2 1],nw,1),nw,nm); else % a 2-d case % horizontal and vertical neighbors only talks_to = [-1 0;0 -1;1 0;0 1]; neighbors_list=identify_neighbors(n,m,nan_list,talks_to); % list of all nodes we have identified all_list=[nan_list;neighbors_list]; % generate sparse array with second partials on row % variable for each element in either list, but only % for those nodes which have a row index > 1 or < n L = find((all_list(:,2) > 1) & (all_list(:,2) < n)); nl=length(L); if nl>0 fda=sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3)+repmat([-1 0 1],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); else fda=spalloc(n*m,n*m,size(all_list,1)*5); end % 2nd partials on column index L = find((all_list(:,3) > 1) & (all_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3)+repmat([-n 0 n],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); end end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); k=find(any(fda(:,nan_list(:,1)),2)); % and solve... B=A; B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k); case 1 % least squares approach with del^2. Build system % for every array element as an unknown, and then % eliminate those which are knowns. % Build sparse matrix approximating del^2 for % every element in A. % is it 1-d or 2-d? if (m == 1) || (n == 1) % a 1-d case u = (1:(nm-2))'; fda = sparse(repmat(u,1,3),bsxfun(@plus,u,0:2), ... repmat([1 -2 1],nm-2,1),nm-2,nm); else % a 2-d case % Compute finite difference for second partials % on row variable first [i,j]=ndgrid(2:(n-1),1:m); ind=i(:)+(j(:)-1)*n; np=(n-2)*m; fda=sparse(repmat(ind,1,3),[ind-1,ind,ind+1], ... repmat([1 -2 1],np,1),n*m,n*m); % now second partials on column variable [i,j]=ndgrid(1:n,2:(m-1)); ind=i(:)+(j(:)-1)*n; np=n*(m-2); fda=fda+sparse(repmat(ind,1,3),[ind-n,ind,ind+n], ... repmat([1 -2 1],np,1),nm,nm); end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); k=find(any(fda(:,nan_list),2)); % and solve... B=A; B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k); case 2 % Direct solve for del^2 BVP across holes % generate sparse array with second partials on row % variable for each nan element, only for those nodes % which have a row index > 1 or < n % is it 1-d or 2-d? if (m == 1) || (n == 1) % really just a 1-d case error('Method 2 has problems for vector input. Please use another method.') else % a 2-d case L = find((nan_list(:,2) > 1) & (nan_list(:,2) < n)); nl=length(L); if nl>0 fda=sparse(repmat(nan_list(L,1),1,3), ... repmat(nan_list(L,1),1,3)+repmat([-1 0 1],nl,1), ... repmat([1 -2 1],nl,1),n*m,n*m); else fda=spalloc(n*m,n*m,size(nan_list,1)*5); end % 2nd partials on column index L = find((nan_list(:,3) > 1) & (nan_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,3), ... repmat(nan_list(L,1),1,3)+repmat([-n 0 n],nl,1), ... repmat([1 -2 1],nl,1),n*m,n*m); end % fix boundary conditions at extreme corners % of the array in case there were nans there if ismember(1,nan_list(:,1)) fda(1,[1 2 n+1])=[-2 1 1]; end if ismember(n,nan_list(:,1)) fda(n,[n, n-1,n+n])=[-2 1 1]; end if ismember(nm-n+1,nan_list(:,1)) fda(nm-n+1,[nm-n+1,nm-n+2,nm-n])=[-2 1 1]; end if ismember(nm,nan_list(:,1)) fda(nm,[nm,nm-1,nm-n])=[-2 1 1]; end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); % and solve... B=A; k=nan_list(:,1); B(k)=fda(k,k)\rhs(k); end case 3 % The same as method == 0, except uses del^4 as the % interpolating operator. % del^4 template of neighbors talks_to = [-2 0;-1 -1;-1 0;-1 1;0 -2;0 -1; ... 0 1;0 2;1 -1;1 0;1 1;2 0]; neighbors_list=identify_neighbors(n,m,nan_list,talks_to); % list of all nodes we have identified all_list=[nan_list;neighbors_list]; % generate sparse array with del^4, but only % for those nodes which have a row & column index % >= 3 or <= n-2 L = find( (all_list(:,2) >= 3) & ... (all_list(:,2) <= (n-2)) & ... (all_list(:,3) >= 3) & ... (all_list(:,3) <= (m-2))); nl=length(L); if nl>0 % do the entire template at once fda=sparse(repmat(all_list(L,1),1,13), ... repmat(all_list(L,1),1,13) + ... repmat([-2*n,-n-1,-n,-n+1,-2,-1,0,1,2,n-1,n,n+1,2*n],nl,1), ... repmat([1 2 -8 2 1 -8 20 -8 1 2 -8 2 1],nl,1),nm,nm); else fda=spalloc(n*m,n*m,size(all_list,1)*5); end % on the boundaries, reduce the order around the edges L = find((((all_list(:,2) == 2) | ... (all_list(:,2) == (n-1))) & ... (all_list(:,3) >= 2) & ... (all_list(:,3) <= (m-1))) | ... (((all_list(:,3) == 2) | ... (all_list(:,3) == (m-1))) & ... (all_list(:,2) >= 2) & ... (all_list(:,2) <= (n-1)))); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,5), ... repmat(all_list(L,1),1,5) + ... repmat([-n,-1,0,+1,n],nl,1), ... repmat([1 1 -4 1 1],nl,1),nm,nm); end L = find( ((all_list(:,2) == 1) | ... (all_list(:,2) == n)) & ... (all_list(:,3) >= 2) & ... (all_list(:,3) <= (m-1))); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3) + ... repmat([-n,0,n],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); end L = find( ((all_list(:,3) == 1) | ... (all_list(:,3) == m)) & ... (all_list(:,2) >= 2) & ... (all_list(:,2) <= (n-1))); nl=length(L); if nl>0 fda=fda+sparse(repmat(all_list(L,1),1,3), ... repmat(all_list(L,1),1,3) + ... repmat([-1,0,1],nl,1), ... repmat([1 -2 1],nl,1),nm,nm); end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); k=find(any(fda(:,nan_list(:,1)),2)); % and solve... B=A; B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k); case 4 % Spring analogy % interpolating operator. % list of all springs between a node and a horizontal % or vertical neighbor hv_list=[-1 -1 0;1 1 0;-n 0 -1;n 0 1]; hv_springs=[]; for i=1:4 hvs=nan_list+repmat(hv_list(i,:),nan_count,1); k=(hvs(:,2)>=1) & (hvs(:,2)<=n) & (hvs(:,3)>=1) & (hvs(:,3)<=m); hv_springs=[hv_springs;[nan_list(k,1),hvs(k,1)]]; end % delete replicate springs hv_springs=unique(sort(hv_springs,2),'rows'); % build sparse matrix of connections, springs % connecting diagonal neighbors are weaker than % the horizontal and vertical springs nhv=size(hv_springs,1); springs=sparse(repmat((1:nhv)',1,2),hv_springs, ... repmat([1 -1],nhv,1),nhv,nm); % eliminate knowns rhs=-springs(:,known_list)*A(known_list); % and solve... B=A; B(nan_list(:,1))=springs(:,nan_list(:,1))\rhs; case 5 % Average of 8 nearest neighbors % generate sparse array to average 8 nearest neighbors % for each nan element, be careful around edges fda=spalloc(n*m,n*m,size(nan_list,1)*9); % -1,-1 L = find((nan_list(:,2) > 1) & (nan_list(:,3) > 1)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-n-1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % 0,-1 L = find(nan_list(:,3) > 1); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-n, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % +1,-1 L = find((nan_list(:,2) < n) & (nan_list(:,3) > 1)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-n+1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % -1,0 L = find(nan_list(:,2) > 1); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([-1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % +1,0 L = find(nan_list(:,2) < n); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % -1,+1 L = find((nan_list(:,2) > 1) & (nan_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([n-1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % 0,+1 L = find(nan_list(:,3) < m); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([n, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % +1,+1 L = find((nan_list(:,2) < n) & (nan_list(:,3) < m)); nl=length(L); if nl>0 fda=fda+sparse(repmat(nan_list(L,1),1,2), ... repmat(nan_list(L,1),1,2)+repmat([n+1, 0],nl,1), ... repmat([1 -1],nl,1),n*m,n*m); end % eliminate knowns rhs=-fda(:,known_list)*A(known_list); % and solve... B=A; k=nan_list(:,1); B(k)=fda(k,k)\rhs(k); end % all done, make sure that B is the same shape as % A was when we came in. B=reshape(B,n,m); % ==================================================== % end of main function % ==================================================== % ==================================================== % begin subfunctions % ==================================================== function neighbors_list=identify_neighbors(n,m,nan_list,talks_to) % identify_neighbors: identifies all the neighbors of % those nodes in nan_list, not including the nans % themselves % % arguments (input): % n,m - scalar - [n,m]=size(A), where A is the % array to be interpolated % nan_list - array - list of every nan element in A % nan_list(i,1) == linear index of i'th nan element % nan_list(i,2) == row index of i'th nan element % nan_list(i,3) == column index of i'th nan element % talks_to - px2 array - defines which nodes communicate % with each other, i.e., which nodes are neighbors. % % talks_to(i,1) - defines the offset in the row % dimension of a neighbor % talks_to(i,2) - defines the offset in the column % dimension of a neighbor % % For example, talks_to = [-1 0;0 -1;1 0;0 1] % means that each node talks only to its immediate % neighbors horizontally and vertically. % % arguments(output): % neighbors_list - array - list of all neighbors of % all the nodes in nan_list if ~isempty(nan_list) % use the definition of a neighbor in talks_to nan_count=size(nan_list,1); talk_count=size(talks_to,1); nn=zeros(nan_count*talk_count,2); j=[1,nan_count]; for i=1:talk_count nn(j(1):j(2),:)=nan_list(:,2:3) + ... repmat(talks_to(i,:),nan_count,1); j=j+nan_count; end % drop those nodes which fall outside the bounds of the % original array L = (nn(:,1)<1)|(nn(:,1)>n)|(nn(:,2)<1)|(nn(:,2)>m); nn(L,:)=[]; % form the same format 3 column array as nan_list neighbors_list=[sub2ind([n,m],nn(:,1),nn(:,2)),nn]; % delete replicates in the neighbors list neighbors_list=unique(neighbors_list,'rows'); % and delete those which are also in the list of NaNs. neighbors_list=setdiff(neighbors_list,nan_list,'rows'); else neighbors_list=[]; end \ No newline at end of file diff --git a/src/lowpf.m b/src/lowpf.m new file mode 100644 index 0000000..09e7af5 --- /dev/null +++ b/src/lowpf.m @@ -0,0 +1,6 @@ +% applies a low pass filter +% [y, n] = lowpf(x, cutoff_frequency) +function [y, n] = lowpf(x, fc) + n = floor(sqrt(0.1024 + fc^2)/fc); + y = filter((1/n)*ones(1,n), 1, x); +end \ No newline at end of file diff --git a/src/mqnr1.m b/src/mqnr1.m new file mode 100644 index 0000000..88e872d --- /dev/null +++ b/src/mqnr1.m @@ -0,0 +1,27 @@ +%Gz = mqnr(y, u, T) não recursivo +function Gz = mqnr(y, u, T) + n = size(y, 1); + for i = 1:size(y, 2) + Y=[]; + fi=[]; + for k=2:n + y1 = y(k-1, i); + u1 = at(u, k-1, i); + Y = [Y; y(k, i)]; + fi = [fi; -y1 u1]; + end + teta(:, i) = (fi'*fi)\fi'*Y; + end; + + uxi = (1:size(u, 2))'; + + for i = 1:size(y, 2) + a1=teta(1, i); + b1=teta(2, i); + + z = tf('z', T, 'variable', 'z^-1'); + j = at(uxi, i); + Gz(i, j) = b1/(1 + a1*z^-1); + Gz(i, j).ioDelay = 1; + end +end diff --git a/src/mqnr2.m b/src/mqnr2.m new file mode 100644 index 0000000..3e04a5f --- /dev/null +++ b/src/mqnr2.m @@ -0,0 +1,31 @@ +%Gz = mqnr(y, u, T) não recursivo +function Gz = mqnr2(y, u, T) + n = size(y, 1); + for i = 1:size(y, 2) + Y=[]; + fi=[]; + for k=3:n + y1 = y(k-1, i); + y2 = y(k-2, i); + u1 = at(u, k-1, i); + u2 = at(u, k-2, i); + Y = [Y; y(k, i)]; + fi = [fi; -y1 -y2 u1 u2]; + end + teta(:, i) = (fi'*fi)\fi'*Y; + end; + + uxi = (1:size(u, 2))'; + + for i = 1:size(y, 2) + a1=teta(1, i); + a2=teta(2, i); + b1=teta(3, i); + b2=teta(4, i); + + z = tf('z', T, 'variable', 'z^-1'); + j = at(uxi, i); + Gz(i, j) = (b1 + b2*z^-1)/(1 + a1*z^-1 + a2*z^-2); + Gz(i, j).ioDelay = 1; + end +end \ No newline at end of file diff --git a/src/plot_fft.m b/src/plot_fft.m new file mode 100644 index 0000000..47ce4f8 --- /dev/null +++ b/src/plot_fft.m @@ -0,0 +1,20 @@ +%plots the normalized fft removing the DC bias +%[handle, maximum_frequency] = plot_fft(y, sampling_frequency) +function [hf, fmax] = plot_fft(X, Fs, varargin) + X = inpaint_nans(X); + L = length(X); + M = floor(L/2); + Y = fft(X - repmat(mean(X), size(X, 1), 1)); + P2 = abs(Y/L); + P1 = P2(1:M+1, :); + p = repmat(max(P1), size(P1, 1), 1); + P1 = P1./p; + P1(1, :) = []; + f = Fs*(1:M)/L; + hf = plot(f,P1,varargin{:}); + title('Fourier Normalizado (AC)') + xlabel('f (Hz)') + ylabel('| FFT |') + [~, index] = max(P1); + fmax = f(index); +end \ No newline at end of file diff --git a/src/plotudo.m b/src/plotudo.m new file mode 100644 index 0000000..b5e6d70 --- /dev/null +++ b/src/plotudo.m @@ -0,0 +1,160 @@ +%[fh1 fh2] = plotudo(t, y, r, e, u, pwm, ...) +%plotudo(t, y, r, e, u, pwm, 1) plota -yD, eD, eI +%plotudo(t, y, r, e, u, pwm, ~, 1) plota fft +%plotudo(t, y, r, e, u, pwm, ~, ~, 1) plota yyaxis +%plotudo(t, y, r, e, u, pwm, ~, ~, ~, t0) tempo zero ? em t0 +function [hf, hfu] = plotudo(t, y, r, e, u, pwm, varargin) + hf = []; + hfu = []; + + T = mean(diff(t)); + ko = round(t(1)/T) + 1; + kf = round(t(end)/T) + 1; + y = y(ko:kf, :); + r = r(ko:kf, :); + e = e(ko:kf, :); + u = u(ko:kf, :); + pwm = pwm(ko:kf, :); + t = t - t(1); + + default = {0, 0, 1, 1}; + custom = [varargin default{(1 + length(varargin)):end}]; + [verbose, fft, yy, start] = custom{:}; + t = t - t(start); + + if verbose + dt = repmat(diff(t)', 1, size(e, 2)); + yD = diff(y)./dt; + yD(end + 1, :) = NaN; + eD = diff(e)./dt; + eD(end + 1, :) = NaN; + eI(1, :) = nan([1, size(e, 2)]); + eI = [eI; cumsum((dt.*(e(1:end-1, :) + e(2:end, :))/2))]; + end + + if ~yy + for k = 1:size(y, 2) + hf(k) = figure; + ax1 = subplot(2, 1, 1); + hold on + grid on + xlabel('Tempo (s)') + if k == 1 + title('') + else + title(sprintf('%d', k)) + end + stairs(t', at(r, ':', k), 'r--', 'LineWidth', 0.5) + stairs(t', y(:, k), 'LineWidth', 1.5, 'Color', [0 0.447 0.741]); + stairs(t', at(r, ':', k), 'r--', 'LineWidth', 0.5); + hold off + legend('r', 'y', 'Location', 'Best'); + legend('boxoff'); + + ax2 = subplot(2, 1, 2); + hold on + grid on + xlabel('Tempo (s)') + if verbose + stairs(t', at(u, ':', k), 'k', 'LineWidth', 0.5); + stairs(t', at(pwm, ':', k), 'ko', 'MarkerSize', 2.5, 'LineWidth', 0.5); + stairs(t', at(e, ':', k), 'LineWidth', 1.5, 'Color', [0 0.447 0.741]); + stairs(t', at(eI, ':', k), 'LineWidth', 0.5, 'Color', [0.9290 0.6940 0.1250]); + stairs(t', at(eD, ':', k), 'LineWidth', 0.5, 'Color', [0.850 0.325 0.098]); + stairs(t', at(-yD, ':', k), 'o', 'MarkerSize', 2.5, 'LineWidth', 0.5, 'Color', [0.850 0.325 0.098]); + plot(t, zeros(size(t)), 'r--', 'LineWidth', 0.5); + legend('u', 'pwm', 'e', 'eI', 'eD', '-yD'); + else + stairs(t', at(u, ':', k), 'k', 'LineWidth', 0.5); + stairs(t', at(pwm, ':', k), 'ko', 'MarkerSize', 2.5, 'LineWidth', 0.5); + %HARD CODE CORE CODE CORE CODE + stairs(t', at(e, ':', k), 'LineWidth', 1.5, 'Color', [0 0.447 0.741]); + plot(t, zeros(size(t)), 'r--', 'LineWidth', 0.5); + legend('u', 'pwm', 'e', 'Location', 'Best'); + legend('boxoff') + end + hold off + linkaxes([ax1 ax2], 'x') + subplot(2, 1, 1) + end + else + %BUG: só normaliza com degrais + %r = r*median(y)/median(r); + + for k = 1:size(y, 2) + hf(k) = figure; + set(hf(k),'defaultAxesColorOrder',[0.6*[0 0.447 0.741]; [0 0 0]]); + + yyaxis left + hold on + %grid on + xlabel('Tempo (s)') + if k == 1 + title('') + else + title(sprintf('%d', k)) + end + stairs(t', at(r, ':', k), 'r--', 'LineWidth', 0.5); + stairs(t', y(:, k), 'LineWidth', 1.5, 'Color', [0 0.447 0.741]); +% hold off +% legend('r', 'y', 'Location', 'Best'); +% legend('boxoff'); + + yyaxis right + hold on + %grid on + xlabel('Tempo (s)') + if verbose + stairs(t', at(u, ':', k), 'k', 'LineWidth', 0.5); + %stairs(t', at(pwm, ':', k), 'ko', 'MarkerSize', 2.5, 'LineWidth', 0.5); + stairs(t', at(e, ':', k), 'LineWidth', 1.5, 'Color', [0 0.447 0.741]); + stairs(t', at(eI, ':', k), 'LineWidth', 0.5, 'Color', [0.9290 0.6940 0.1250]); + stairs(t', at(eD, ':', k), 'LineWidth', 0.5, 'Color', [0.850 0.325 0.098]); + stairs(t', at(-yD, ':', k), 'o', 'MarkerSize', 2.5, 'LineWidth', 0.5, 'Color', [0.850 0.325 0.098]); + plot(t, zeros(size(t)), 'r--', 'LineWidth', 0.5); + legend('u', 'e', 'eI', 'eD', '-yD'); + else + stairs(t', at(u, ':', k), 'k', 'LineWidth', 0.5); + stairs(t', at(pwm, ':', k), 'ko', 'MarkerSize', 2.5, 'LineWidth', 0.5); + end + legend('r', 'y', 'u', 'pwm', 'Location', 'Best'); + legend('boxoff') + hold off + end + end + xlim([t(1) t(end)]) + + %FOURIER + if fft + for k = 1:size(y, 2) + hfu(k) = figure; + colormap('default') + hold on + %grid on + if verbose + plot_fft( y( ':', k), 1/T, 'LineWidth', 1.5, 'Color', [0 0.447 0.741]); + plot_fft(at(r, ':', k), 1/T, 'r--', 'LineWidth', 0.5); + plot_fft(at(u, ':', k), 1/T, 'k', 'LineWidth', 0.5); + plot_fft(at(pwm, ':', k), 1/T, 'ko', 'MarkerSize', 4, 'LineWidth', 0.5); + plot_fft(at(e, ':', k), 1/T, 'x', 'MarkerSize', 4, 'Color', [0 0.447 0.741]); + plot_fft(at(eI, ':', k), 1/T, 'x', 'MarkerSize', 4, 'Color', [0.9290 0.6940 0.1250]); + plot_fft(at(eD, ':', k), 1/T, 'x', 'MarkerSize', 4, 'Color', [0.850 0.325 0.098]); + plot_fft(at(-yD, ':', k), 1/T, 'o', 'MarkerSize', 4, 'Color', [0.850 0.325 0.098]); + legend('y', 'r', 'u', 'pwm', 'e', 'eI', 'eD', '-yD'); + else + plot_fft( y( ':', k), 1/T, 'LineWidth', 1.5, 'Color', [0 0.447 0.741]); + plot_fft(at(r, ':', k), 1/T, 'r--', 'LineWidth', 0.5); + plot_fft(at(u, ':', k), 1/T, 'k', 'LineWidth', 0.5); + plot_fft(at(pwm, ':', k), 1/T, 'ko', 'MarkerSize', 4, 'LineWidth', 0.5); + legend('y', 'r', 'u', 'pwm', 'Location', 'Best'); + legend('boxoff') + end + if k == 1 + title('') + else + title(sprintf('%d', k)) + end + hold off + end + end +end \ No newline at end of file diff --git a/src/qshift.m b/src/qshift.m new file mode 100644 index 0000000..286f1a7 --- /dev/null +++ b/src/qshift.m @@ -0,0 +1,29 @@ +%shifts and adds signal x, using a poly of backward shifts +%if poly is of order n, and there is no fill, will drop the first n values +%if there is a fill, it could be 0: to fill with zeros OR 1: to circshift +%poly could also be a Lag Operator Polynominal +%y = qshift(x, poly, fill?) +%Ex: diff(x) == qshift(x, [1 -1]) +%see also: LagOp +function y = qshift(x, poly, varargin) + if isa(poly, 'LagOp') + n = poly.Degree + 1; + polyarr = zeros([1, n]); + for i = 1:n + polyarr(i) = poly.Coefficients{i-1}; + end + poly = polyarr; + end + n = length(poly); + y = zeros(size(x)); + for i = 1:n + y = y + poly(i)*wshift('1d', x, -(i-1)); + end + if nargin == 3 + if varargin{1} == 0 + y(1:n-1) = 0; + end + else + y(1:n-1) = []; + end +end \ No newline at end of file diff --git a/src/readlino.m b/src/readlino.m new file mode 100644 index 0000000..c31e5c7 --- /dev/null +++ b/src/readlino.m @@ -0,0 +1,9 @@ +%readlino(serial_port) +function y = readlino(s) + flushinput(s); + flushoutput(s); + fwrite(s, '7', 'uint8'); + fwrite(s, 10, 'uint8'); + resposta = fread(s, 2); + y = double(bitor(bitshift(uint16(resposta(1)),8),uint16(resposta(2)))); +end \ No newline at end of file diff --git a/src/readsim.m b/src/readsim.m new file mode 100644 index 0000000..e5c1f1a --- /dev/null +++ b/src/readsim.m @@ -0,0 +1,18 @@ +%simulates Gz by global y, v, k +function yk = readsim(Gz) + global y pwm k + yk = nan(1, size(Gz, 1)); + idv = 1:size(Gz, 2); + for i=1:size(Gz, 1) + [NUM, DEM] = tfdata(Gz(i), 'v'); + Nnum = length(DEM); + Ndem = length(NUM); + d = totaldelay(Gz(i, at(idv, i))); + if k > d + yk(1, i) = -DEM(2:Ndem)*at(y, k-1: -1: k-Ndem+1, i) ... + +NUM(1:Nnum)*at(pwm, k-d-Ndem+Nnum: -1: k-d-Ndem+1, i); + else + yk(1, i) = at(y, k-1, i); + end + end +end \ No newline at end of file diff --git a/src/relay_info.m b/src/relay_info.m new file mode 100644 index 0000000..656fea2 --- /dev/null +++ b/src/relay_info.m @@ -0,0 +1,63 @@ +function [Gjw, w, d, a, eps] = relay_info(y, u, T, varargin) + %[Gjw, w] = relay_info(y, u, T) + try %cleaning this once + n = length(y); + settled = (1:n > 0)'; % no shame + u = u - mean(u(settled)); + spin = round(2*u/(peak2peak(u))); +% spin = round(2*(u - mean(u))/(peak2peak(u))); + e = mean(y(settled))-y; + edg = settled.*[0; diff(spin)]/2; + bet = logical(edg) | logical(circshift(edg, -1)); +% figure +% hold on +% plot(spin) +% plot(edg) + if nargin < 4 + d = mean((u(logical(edg)) - mean(u)).*edg(logical(edg))); + else + d = varargin{1}; + end + epsaux = e(bet).*(edg(bet) + circshift(edg(bet), -1)); + if ~isempty(epsaux) % todo: if find 1 cycle + eo = mean(e(settled)); + eps = max(0, mean(epsaux)); + end + % for measuring a, find the corresponding peak in beetween two edges! + edg_id = sign(edg).*sign(spin.*settled).*(1:n)'; + edg_id(edg_id == 0) = []; + edg_delta = []; + aaux = []; + for ide = 1:length(edg_id)-1 + fst = edg_id(ide); + lst = edg_id(ide+1)-1; + edg_delta = [edg_delta; lst - fst + 1]; + aaux(ide, 1) = max(sign(edg(fst))*e(fst:lst)); + end + if ~isempty(aaux) % todo: if find 1 cycle + a = median(aaux); + else + a = peak2peak(e(round(end/2):end))/2; + end + + if ~mod(length(edg_delta), 2) + edg_delta(end) = []; + end + edg_delta = qshift(edg_delta, [1, 1]); + w = 2*pi/(mean(edg_delta)*T); +% w = 2*pi*medfreq(u-mean(u), 1/T) %which one is less worst? +% w = pi*maxfreq(u)/T; + Gjw = -pi/(4*d)*sqrt(a^2 - eps^2) - 1j*pi/(4*d)*eps; +% Gjw = -1/(2*d/(pi*a)*(sqrt(1 - ((eps + eo)/a)^2) + sqrt(1 - ((eps - eo)/a)^2)) - 1j*4*d*eps/(pi*a^2)); + %Lh = (asin(eps/a)/w); % this is what the delay was supposed to be + %L = 2*T*finddelay(y, u) - Lh; % the rest is lag + %L = T; % let's hard code here + disp([' d = ' num2str(d) ', eps = ' num2str(eps) ', eo = ' num2str(eo) ', a = ' num2str(a) ',' 10 ' w = ' num2str(w) ', Gjw = ' num2str(abs(Gjw)) ' <' num2str(angle(Gjw)) 10]) + catch ME % todo: find the Black Swan + eps = NaN; + a = NaN; + Gjw = NaN; + w = NaN; + disp(['Broke! ' ME.message]) + end +end \ No newline at end of file diff --git a/src/startcom.m b/src/startcom.m new file mode 100644 index 0000000..bec72f9 --- /dev/null +++ b/src/startcom.m @@ -0,0 +1,37 @@ +%Attempts to connect with plant or model, in that order +%[stop, read, write] = startcom(COM) +%[stop, read, write] = startcom(COM, Gz) +function [stop, read, write, plant] = startcom(COM, varargin) + if nargin >= 2 + Gz = varargin{1}; + end + if nargin >= 3 + noise_amp = varargin{2}; + else + noise_amp = 0; + end + try + s = serial(COM,'BaudRate',19200); + s.terminator = 'LF'; + s.RecordDetail = 'verbose'; + s.RecordName = 'comlog.txt'; + out = instrfind(s); + if strcmp(out.status, 'closed') + fclose(instrfind); + fopen(s); + end + record(s, 'off'); + read = @() readlino(s); + write = @(duty) writelino(s, duty); + stop = @() stopino(s); + plant = true; + read(); + catch ME1 + errors = textscan(ME1.message, '%[^\n]', 1); + disp([errors{end}{:}]); Gz + read = @() readsim(Gz) + noise_amp*randn(); + write = @(duty) writesim(duty); + stop = 0; + plant = false; + end +end \ No newline at end of file diff --git a/src/step_info.m b/src/step_info.m new file mode 100644 index 0000000..c30f1b4 --- /dev/null +++ b/src/step_info.m @@ -0,0 +1,18 @@ +function [Mu, ts, tr, tp, itae] = step_info(y, u, T, varargin) + %[Gjw, w] = step_info(y, u, T) + zero = find(u, 1); + fim = length(u); + t = 0:T:(fim-1)*T; + [ymax, peak] = max(y); + ymed = median(y); + sett = fim - find(flip(y) > 1.02*ymed | flip(y) < 0.98*ymed, 1); + ts = T*(sett - zero); + rise = find(y > ymed, 1); + tr = T*(rise - zero); + Mu = 100*(ymax - ymed)/ymed; + tp = T*(peak - zero); + itae = sum(abs(y - ymed).*(t'))*T; + umax = max(u); + umed = median(u); + disp([' Mu = ' num2str(Mu) ', ts = ' num2str(ts) ', tr = ' num2str(tr) ', tp = ' num2str(tp) ', itae = ' num2str(itae) ', uo = ' num2str(u(zero)) ', udc = ' num2str(umed)]) +end \ No newline at end of file diff --git a/src/stopino.m b/src/stopino.m new file mode 100644 index 0000000..19fe892 --- /dev/null +++ b/src/stopino.m @@ -0,0 +1,7 @@ +%stopino(serial_port) +function stopino(s) + flushinput(s); + flushoutput(s); + fwrite(s, '2', 'uint8'); + fwrite(s, 10, 'uint8'); +end \ No newline at end of file diff --git a/src/subsp.m b/src/subsp.m new file mode 100644 index 0000000..0f199f8 --- /dev/null +++ b/src/subsp.m @@ -0,0 +1,14 @@ +%substitution of a poly on x through poly a. result is a new poly on y +%y = subsp(x, a) +%Ex: subsp([1 0 1 0], [1 -1]) == [1 -3 4 -2] +function y = subsp(x, a) + n = length(x); + m = length(a); + o = (n-1)*(m-1) + 1; + y = zeros(n, o); + for i = 1:(n-1) + y(i, i:o) = x(i)*convp(a, n-i); + end + y = sum(y); + y(end) = x(end) + y(end); +end \ No newline at end of file diff --git a/src/toString.m b/src/toString.m new file mode 100644 index 0000000..c36a0f0 --- /dev/null +++ b/src/toString.m @@ -0,0 +1,586 @@ +function str = toString(var, varargin) +% TOSTRING produce string representation of any datatype +% +% S = TOSTRING(A) produces a string representation of A, where +% class(A) can be one of +% +% double, single +% logical, +% char, +% int8, uint8 +% int16, uint16 +% int32, uint32 +% int64, uint64 +% cell, +% struct, +% function_handle, +% (user-implemented class name) +% +% The default string represenation is as verbose as possible. +% That means the contents of structure fields, cell array +% entries, etc. are representated in fully expanded form. +% +% S = TOSTRING(A, 'disp') produces a string representaion that +% is identical to what the command 'disp(A)' would produce. +% +% S = TOSTRING(A, 'compact') or S = TOSTRING(A, N) (with N a positive +% integer) limits the number of digits displayed in numerical arrays +% to either 4 ('compact') or N. +% +% +% EXAMPLE 1: +% +% >> a = struct('someField', uint32(10*rand(2)), 'otherField', {{[]}}); +% >> S = toString(a) +% +% S = +% +% 1x1 struct: +% someField: [9 7] +% [2 2] +% otherField: { [] } +% +% +% >> S = toString(a, 'disp') +% +% S = +% +% someField: [2x2 uint32] +% otherField: [] +% +% +% EXAMPLE 2: +% +% >> a = rand(2,2,2,2); +% >> S = toString(rand(2,2,3,2) +% +% S = +% +% (:,:,1,1) = +% [5.501563428984222e-01 5.870447045314168e-01] +% [6.224750860012275e-01 2.077422927330285e-01] +% +% (:,:,1,2) = +% [4.356986841038991e-01 9.233796421032439e-01] +% [3.111022866504128e-01 4.302073913295840e-01] +% +% +% (:,:,2,1) = +% [3.012463302794907e-01 2.304881602115585e-01] +% [4.709233485175907e-01 8.443087926953891e-01] +% +% (:,:,2,2) = +% [1.848163201241361e-01 9.797483783560852e-01] +% [9.048809686798929e-01 4.388699731261032e-01] +% +% +% EXAMPLE 3: +% +% >> a = cellfun(@(~)rand(3), cell(2), 'UniformOutput',false); +% >> a{end} = cell(2); +% >> a{end}{end} = @sin; +% >> S = toString(a, 2) +% +% S = +% +% { [0.01 0.92 0.42] [0.61 0.24 0.77] } +% { [0.60 0.00 0.46] [0.19 0.92 0.19] } +% { [0.39 0.46 0.77] [0.74 0.27 0.29] } +% { } +% { [0.32 0.04 0.47] { [] [] } } +% { [0.78 0.18 0.15] { [] @sin } } +% { [0.47 0.72 0.34] } +% +% +% See also disp, num2str, func2str, sprintf. + + + +% If you find this work useful and want to make a donation: +% https://www.paypal.me/RodyO/3.5 + + + +% Please report bugs and inquiries to: +% +% Name : Rody P.S. Oldenhuis +% E-mail : oldenhuis@gmail.com (personal) +% oldenhuis@luxspace.lu (professional) +% Affiliation: LuxSpace sàrl +% Licence : BSD + + +% If you find this work useful and want to show your appreciation: +% https://www.paypal.me/RodyO/3.5 + + +% Authors +%{ +Rody Oldenhuis (oldenhuis@gmail.com) +Clark Williams (rich.dick.clark@gmail.com) +%} + + +% Changelog +%{ +2014/February/14 (Rody Oldenhuis) +- CHANGED: Included "Authors" field, donation link, etc. +- CHANGED: Removed constructor from enum types, as it cannot be called directly +- CHANGED: Made enum types respond differently to "compact" notation +- FIXED: Integer types with user-defined accuracy never not assigned +- FIXED: warning about integers with user-defined accuracy was issued also on + recursive call (relevant for user-defined classes). +- FIXED: missing space in class header + +2014/February/13 (Clark Williams / Rody Oldenhuis) +- NEW: support for enum types + +2012/October/12 (Rody Oldenhuis) +- NEW: support for sparse matrices + +2012/October/11 (Rody Oldenhuis) +- First version + +%} + + + +% If you find this work useful and want to make a donation: +% https://www.paypal.me/RodyO/3.5 + + + + %% Initialize + + multiD = false; + numDigits = inf; % maximum precision + if nargin >= 2 + if ischar(varargin{1}) + + switch lower(varargin{1}) + + % return same as disp would print + case 'disp' + str = evalc('disp(var)'); + % instead of char(10) as \n, output multi-row char array + C = textscan(str, '%s',... + 'delimiter', '\r\n',... + 'MultipleDelimsAsOne', true); + str = char(C{1}); + return; + + % return same as disp would print + case 'compact' + numDigits = 4; % + + % RECURSIVE CALL (FOR MULTI-D ARRAYS) + % LEAVE UNDOCUMENTED + case 'recursive_call' + multiD = true; + indexString = varargin{2}; + numDigits = varargin{3}; + + otherwise + error(... + 'toString:unknown_option',... + 'Unknown option: %s.', varargin{1}); + end + + % Manually pass number of digits + elseif isscalar(varargin{1}) && isnumeric(varargin{1}) + numDigits = max(0, round(varargin{1})); + + else + error(... + 'toString:invalid_second_argument',... + 'Second argument to toString must be a string.'); + end + end + + + %% Generate strings + + % handle multi-D variables + if ~isstruct(var) % NOT for structures + if ndims(var)>=3 + + a = repmat({':'}, 1,ndims(var)-3); + + str = []; + for ii = 1:size(var,3) + if ~multiD % first call + str = char(... + str, ... + toString( ... + squeeze(var(:,:,ii,a{:})), ... + 'recursive_call', ['(:,:,' num2str(ii)],... + numDigits)... + ); + + else % subsequent calls + str = char(... + str, ... + toString( ... + squeeze(var(:,:,ii,a{:})), ... + 'recursive_call', [indexString ',', num2str(ii)],... + numDigits), ... + ''); + end + end + + return + + elseif multiD % last call + str = char(... + [indexString ') = '],... + toString(var, numDigits)); + return + + end + end + + % Empties first + if isempty(var) + + if ischar(var) + str = '""'; + + elseif iscell(var) + str = '{}'; + + % FIXME: delegate this somehow to where structs are handled + elseif isstruct(var) + fn = fieldnames(var); + if ~isempty(fn) + str = char(... + 'empty struct with fields:',... + fn{:}); + else + str = 'empty struct'; + end + + else + str = '[]'; + + end + + return + end + + % simplest case: char + if ischar(var) + quote = repmat('"', size(var,1),1); + str = [quote var quote]; + return + end + + % ordinary numeric or logical array can be handled by num2str + if isnumeric(var) || islogical(var) + + % integers + if isinteger(var) || islogical(var) + + str = num2str(var); + if isfinite(numDigits) + warning(... + 'toString:numdigits_on_int',... + 'The number of digits only applies to non-integer data. Ignoring...'); + end + + else + if ~isfinite(numDigits) + if issparse(var) + % just use the disp version + str = toString(var, 'disp'); + + else + if isa(var, 'double') + str = num2str(var, '%+17.15e '); + elseif isa(var, 'single') + str = num2str(var, '%+9.7e '); + else + error(... + 'toString:unknown_class',... + ['Unsupported numeric class: ''', class(var), '''.']); + end + end + else + frmt = ['%' num2str(numDigits+2) '.' num2str(numDigits), 'f ']; + if issparse(var) + % just use the disp version + str = evalc('disp(var)'); + + % apply the correct number of digits + str = textscan(str, '%s %f', ... + 'delimiter', ' \r\n',... + 'MultipleDelimsAsOne', true); + str{2} = num2str(str{2}, frmt); + str = [char(str{1}) repmat(' ', size(str{1},1),1) str{2}]; + + else + str = num2str(var, frmt); + end + + end + end + + if numel(var) > 1 + brO = repmat('[',size(str,1),1); + brC = brO; brC(:) = ']'; + str = [brO str brC]; + end + + return; + + end + + % Cell arrays + if iscell(var) + + strreps = cellfun(@(x)toString(x,numDigits), var, 'UniformOutput', false); + + rows = max(cellfun(@(x)size(x,1), strreps),[],2); + cols = max(cellfun(@(x)size(x,2), strreps),[],1); + + str = []; + for ii = 1:size(strreps,1) + + space = repmat(' ', rows(ii),2); + braceO = repmat('{', rows(ii),1); + braceC = braceO; braceC(:) = '}'; + + newentry = braceO; + for jj = 1:size(strreps,2) + newentry = [... + newentry,... + space,... + center(strreps{ii,jj}, rows(ii), cols(jj))]; %#ok FIXME: growing array + end + newentry = [newentry space braceC]; %#ok FIXME: growing array + + emptyline = ['{' repmat(' ', 1,size(newentry,2)-2) '}']; + if ii == 1 + str = char(newentry); + + else + if rows(ii) == 1 + str = char(str, newentry); + else + str = char(str, emptyline, newentry); + end + end + + end + + return + end + + % function handles + if isa(var, 'function_handle') + str = func2str(var); + if str(1) ~= '@' + str = ['@' str]; end + return + end + + % structures + if isstruct(var) + + fn = fieldnames(var); + + sz = num2str(size(var).'); + sz(:,2) = 'x'; sz = sz.'; + sz = sz(:).'; sz(end) = []; + + if isempty(fn) + if numel(var) == 0 + str = 'empty struct'; + else + str = [sz ' struct with no fields.']; + end + + elseif numel(var) == 1 + str = [sz ' struct:']; + str = append_list(var, str,fn,numDigits); + + else + str = char(... + [sz ' struct array with fields:'],... + fn{:}); + end + + return; + end + + + % If we end up here, we've been given a classdef'ed object + % -------------------------------------------------------- + + name = class(var); + + supers = superclasses(var); + methds = methods(var); + props = properties(var); + evnts = events(var); + enums = enumeration(var); + + % We'll be calling toString recursively; kill this warning, because it + % doesn't apply to this case + warnState = warning('off', 'toString:numdigits_on_int'); + + % Compact display for enums + if isfinite(numDigits) && ~isempty(enums) + str = [name '.' char(var)]; + % Don't forget to reinstate this warning + warnint(warnState); + return + end + + % Class header + if numel(supers) > 1 + supers = [ + cellfun(@(x) [x ' -> '], supers(1:end-1), 'UniformOutput', false) + supers(end)]; + supers = [supers{:}]; + elseif ~isempty(supers) + supers = supers{:}; + end + if (isempty(supers)) % BUGFIX: (Clark) empties were not handled nicely + str = ['class ' name ', no subclasses.']; + else + str = ['class ' name ', subclass of ' supers]; + end + + % Properties + if ~isempty(props) + str = char(str, '', 'Properties:', '------------'); + str = append_list(var, str,props, numDigits); + else + str = char(str, '','', '<< No public properties >>'); + end + + % Methods + if ~isempty(methds) + str = char(str, '', '', 'Methods:', '------------'); + + % NOTE: remove constructur for enums + if ~isempty(enums) + methds = methds(~strcmpi(methds, name)); end + + methds = append_string(right_align(methds), '()'); + str = char(str, methds{:}); + else + str = char(str, '','', '<< No public methods >>'); + end + + % Enumerations + if ~isempty(enums) + str = char(str, '', '', 'Enumerations:', '------------'); + + enumlabels = cell(size(enums)); + for k = 1 : numel(enums) + % BUGFIX: (Clark) highlight current value + if var == enums(k) + enumlabels{k} = ['<<' char(enums(k)) '>>']; + else + + enumlabels{k} = [' ' char(enums(k)) ' ']; + end + end + enumlabels = right_align(enumlabels); + + str = char(str, enumlabels{:}); + else + str = char(str, '','', '<< No public enumerations >>'); + end + + % Events + if ~isempty(evnts) + str = char(str, '','', 'Events:', '------------'); + evnts = right_align(evnts); + str = char(str, evnts{:}); + else + str = char(str, '','', '<< No public events >>'); + end + + % Don't forget to reinstate this warning + warning(warnState); + +end + + + +% STRING MANIPULATION +% -------------------------------------------------- + + +% pad (cell) string with spaces according to required field width +function str = prepend_space(fw, str) + if iscell(str) + str = cellfun(@(x) prepend_space(fw,x), str, 'UniformOutput', false); + else + str = [repmat(' ', size(str,1),fw-length(str)) str]; + end +end + + +% make a displayable "block" of a single key and possibly many values +function str = make_block(key, value) + + if size(value,1) > 1 + key = [key; repmat(' ', size(value,1)-1, size(key,2))]; end + + str = [key value]; +end + + +% right-align all entries in a cell string +function list = right_align(list) + list = prepend_space(max(cellfun(@length,list)), list); +end + + +% center-align (horizontal and vertical) a character array +% according to given block size +function str = center(str, rows,cols) + + [sz1, sz2] = size(str); + + if sz2 < cols || sz1 < rows + + ctr = max(1, ceil([rows/2-(sz1-1)/2 cols/2-(sz2-1)/2])); + newstr = repmat(' ', rows,cols); + + for ii = 1:sz1 + newstr(ctr(1)+ii-1, (0:length(str(ii,:))-1)+ctr(2) ) = str(ii,:); end + + str = newstr; + end + +end + + +% append a string to every entry in a cell string +function list = append_string(list, string) + if iscell(list) + list = cellfun(@(x) [x string], list, 'UniformOutput', false); + else + list = [list string]; + end +end + + +% append a set of keys and their evaluated values to a list +function str = append_list(var, str,list,numDigits) + + for ii = 1:size(list,1) + list{ii,2} = toString(var.(list{ii,1}),numDigits); end + + list(:,1) = append_string(right_align(list(:,1)), ': '); + + for ii = 1:size(list,1) + str = char(str, make_block(list{ii,:})); end + +end + + diff --git a/src/writelino.m b/src/writelino.m new file mode 100644 index 0000000..7b37a8b --- /dev/null +++ b/src/writelino.m @@ -0,0 +1,8 @@ +%writelino(serial_port, duty_percent) +function writelino(s, value) + flushinput(s); + flushoutput(s); + fwrite(s, '5', 'uint8'); + fwrite(s, value, 'uint8'); + fwrite(s, 10, 'uint8'); +end \ No newline at end of file diff --git a/src/writesim.m b/src/writesim.m new file mode 100644 index 0000000..e345f61 --- /dev/null +++ b/src/writesim.m @@ -0,0 +1,3 @@ +%nop +function writesim(~) +end \ No newline at end of file diff --git a/triangularPulseInv.m b/triangularPulseInv.m new file mode 100644 index 0000000..e067407 --- /dev/null +++ b/triangularPulseInv.m @@ -0,0 +1,9 @@ +%TRIANGULARPULSEINV x = triangularPulseInv( a, b, c, y ) +function x = triangularPulseInv( a, b, c, y ) + if y > 1 || y < 0 + x = [NaN NaN]; + else + x = [a + y*(b - a) b + (1 - y)*(c - b)]; + end +end + diff --git a/ventilador.m b/ventilador.m new file mode 100644 index 0000000..5f8db34 --- /dev/null +++ b/ventilador.m @@ -0,0 +1,137 @@ +function ventilador(block) + +%MSFUNTMPL_BASIC A Template for a Level-2 MATLAB S-Function +% The MATLAB S-function is written as a MATLAB function with the +% same name as the S-function. Replace 'msfuntmpl_basic' with the +% name of your S-function. +% +% It should be noted that the MATLAB S-function is very similar +% to Level-2 C-Mex S-functions. You should be able to get more +% information for each of the block methods by referring to the +% documentation for C-Mex S-functions. +% +% Copyright 2003-2010 The MathWorks, Inc. + +%% +%% The setup method is used to set up the basic attributes of the +%% S-function such as ports, parameters, etc. Do not add any other +%% calls to the main body of the function. +%% +addpath(genpath('src')); % add readlino and writelino functions +setup(block); + +%endfunction + +%% Function: setup =================================================== +%% Abstract: +%% Set up the basic characteristics of the S-function block such as: +%% - Input ports +%% - Output ports +%% - Dialog parameters +%% - Options +%% +%% Required : Yes +%% C-Mex counterpart: mdlInitializeSizes +%% +function setup(block) +beep off + +% Register number of ports +block.NumInputPorts = 1; +block.NumOutputPorts = 1; + +% Setup port properties to be inherited or dynamic +block.SetPreCompInpPortInfoToDynamic; +block.SetPreCompOutPortInfoToDynamic; + +% Override input port properties +block.InputPort(1).Dimensions = 1; +block.InputPort(1).DatatypeID = 0; % double +block.InputPort(1).Complexity = 'Real'; +block.InputPort(1).DirectFeedthrough = true; + +% Override output port properties +block.OutputPort(1).Dimensions = 1; +block.OutputPort(1).DatatypeID = 0; % double +block.OutputPort(1).Complexity = 'Real'; + +% Register parameters +block.NumDialogPrms = 1; + +% Register sample times +% [0 offset] : Continuous sample time +% [positive_num offset] : Discrete sample time +% +% [-1, 0] : Inherited sample time +% [-2, 0] : Variable sample time +block.SampleTimes = [-1 0]; + +% Specify the block simStateCompliance. The allowed values are: +% 'UnknownSimState', < The default setting; warn and assume DefaultSimState +% 'DefaultSimState', < Same sim state as a built-in block +% 'HasNoSimState', < No sim state +% 'CustomSimState', < Has GetSimState and SetSimState methods +% 'DisallowSimState' < Error out when saving or restoring the model sim state +block.SimStateCompliance = 'DefaultSimState'; + +%% ----------------------------------------------------------------- +%% The MATLAB S-function uses an internal registry for all +%% block methods. You should register all relevant methods +%% (optional and required) as illustrated below. You may choose +%% any suitable name for the methods and implement these methods +%% as local functions within the same file. See comments +%% provided for each function for more information. +%% ----------------------------------------------------------------- + +block.RegBlockMethod('Start', @Start); +block.RegBlockMethod('Outputs', @Outputs); % Required +block.RegBlockMethod('Terminate', @Terminate); % Required + +%end setup + +%% +%% Start: +%% Functionality : Called once at start of model execution. If you +%% have states that should be initialized once, this +%% is the place to do it. +%% Required : No +%% C-MEX counterpart: mdlStart +%% +function Start(block) +COM = block.DialogPrm(1).Data; % get the COM port number +s = serial(COM,'BaudRate',19200); % create the serial handler +s.terminator = 'LF'; +out = instrfind(s); +if strcmp(out.status, 'closed') + fclose(instrfind); + fopen(s); +end +set_param(block.BlockHandle, 'UserData', s); + +%end Start + +%% +%% Outputs: +%% Functionality : Called to generate block outputs in +%% simulation step +%% Required : Yes +%% C-MEX counterpart: mdlOutputs +%% +function Outputs(block) +s = get_param(block.BlockHandle, 'UserData'); % get serial handler +writelino(s, block.InputPort(1).Data) % write to plant +block.OutputPort(1).Data = readlino(s); % read from plant + +%end Outputs + +%% +%% Terminate: +%% Functionality : Called at the end of simulation for cleanup +%% Required : Yes +%% C-MEX counterpart: mdlTerminate +%% +function Terminate(block) +s = get_param(block.BlockHandle, 'UserData'); % get serial handler +stopino(s); + +%end Terminate \ No newline at end of file