jsonencode of state space model

2 visualizaciones (últimos 30 días)
Jeff Mandel
Jeff Mandel el 12 de Abr. de 2025
Comentada: Paul el 15 de Abr. de 2025
I am trying to store data I need to persist between calls to a microservice in a Java HashMap. To do this, my data structure needs to be serialized/deserialized, and jsonencode/jsondecode seemed like a reasonable option (yes, I know about getByteStreamFromArray, but it's undocumented). One of the elements of my data structure is a state space model:
>> sys = ss(A,B,C,D)
ss with properties:
A: [4×4 double]
B: [4×1 double]
C: [0 0 0 1.9531e+03]
D: 0
E: []
Offsets: []
Scaled: 0
StateName: {4×1 cell}
StatePath: {4×1 cell}
StateUnit: {4×1 cell}
InternalDelay: [0×1 double]
InputDelay: 0
OutputDelay: 0
InputName: {''}
InputUnit: {''}
InputGroup: [1×1 struct]
OutputName: {''}
OutputUnit: {''}
OutputGroup: [1×1 struct]
Notes: [0×1 string]
UserData: []
Name: ''
Ts: 0.0167
TimeUnit: 'seconds'
SamplingGrid: [1×1 struct]
>> sys1 = jsondecode(jsonencode(sys))
struct with fields:
A: [4×4 double]
B: [4×1 double]
C: [4×1 double]
D: 0
E: []
Offsets: []
Scaled: 0
StateName: {4×1 cell}
StatePath: {4×1 cell}
StateUnit: {4×1 cell}
InternalDelay: []
InputDelay: 0
OutputDelay: 0
InputName: {''}
InputUnit: {''}
InputGroup: [1×1 struct]
OutputName: {''}
OutputUnit: {''}
OutputGroup: [1×1 struct]
Notes: []
UserData: []
Name: ''
Ts: 0.0167
TimeUnit: 'seconds'
SamplingGrid: [1×1 struct]
Now, this is really close, but not close enough:
>> u=ones(1,100);
>> out=lsim(sys,u);
>> out=lsim(sys1,u);
Error using lsim (line 93)
Not enough input arguments.
Is there a way on convincing MATLAB that sys1 is a "ss with properties" rather than a "struct with fields"? Preferably something more elegant than creating a new model and copying all the fields of the structure.
  2 comentarios
Paul
Paul el 14 de Abr. de 2025
Also, the encode->decode operation changes row vectors to column vectors, so you'll have to deal with that.
A = rand(4);
B = rand(4,2);
C = [0,0,0,1];
D = [1,2];
sys = ss(A,B,C,D);
sys1 = jsondecode(jsonencode(sys));
sys1.C
ans = 4×1
0 0 0 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
sys1.D
ans = 2×1
1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Interestingly enough, there is no problem if C and D are matrices
C = [0,0,0,1;0,0,0,2];
D = [1,2;3 4];
sys = ss(A,B,C,D);
sys1 = jsondecode(jsonencode(sys));
sys1.C
ans = 2×4
0 0 0 1 0 0 0 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
sys1.D
ans = 2×2
1 2 3 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Is that a bug for the case where C and D are vectors?
Rik
Rik el 14 de Abr. de 2025
This isn't a bug for vectors, but a quirk of the JSON standard. Since it only supports vectors, matrices are encoded as lists of vectors. Mathworks could have chosen to write column vectors as a list of lists, but that is uncommon and should probably be hidden behind an optional parameter, since the direction of vectors wouldn't matter in most applications where data is converted to JSON.
jsonencode([1 2 3])
ans = '[1,2,3]'
jsonencode([1;2;3])
ans = '[1,2,3]'
jsonencode([1 2;3 4])
ans = '[[1,2],[3,4]]'
You could write your own implementation of a JSON encoder of course. That is a lot harder than a JSON parser, but with a bit of dedication it is not too hard to cover most cases (it's the exceptions that will get you).

Iniciar sesión para comentar.

Respuestas (1)

Rik
Rik el 14 de Abr. de 2025
A=rand(4);
B=rand(4);
C=[0 0 0 1.9531e+03];
D=0;
sys = ss(A,B,C,D);
sys_info = jsondecode(jsonencode(sys));
try
sys2 = ss(sys_info.A,sys_info.B,sys_info.C,sys_info.D);
catch ME
warning(['Because I don''t have a nice example, the assignment above doesn''t work.\n'...
'Instead, it fails with this error:\n%s'],ME.message)
sys2 = ss(A,B,C,D);
end
Warning: Because I don't have a nice example, the assignment above doesn't work.
Instead, it fails with this error:
The "A" and "C" matrices must have the same number of columns.
properties_list = fieldnames(sys_info);
for n=1:numel(properties_list)
% skip ABCD
if ismember(properties_list{n},{'A','B','C','D'}),continue,end
% copy over the property
sys2.(properties_list{n})=sys_info.(properties_list{n});
end
sys2
sys2 = A = x1 x2 x3 x4 x1 0.7053 0.2628 0.4748 0.6195 x2 0.5293 0.3003 0.2007 0.7605 x3 0.4226 0.9391 0.1972 0.8843 x4 0.9208 0.6175 0.3733 0.5079 B = u1 u2 u3 u4 x1 0.3459 0.6169 0.9265 0.7459 x2 0.4968 0.2716 0.6064 0.4274 x3 0.953 0.9765 0.4011 0.5137 x4 0.7184 0.5531 0.187 0.4571 C = x1 x2 x3 x4 y1 0 0 0 1953 D = u1 u2 u3 u4 y1 0 0 0 0 Continuous-time state-space model.
  3 comentarios
Rik
Rik el 14 de Abr. de 2025
I don't know about expected, but it isn't a full blown bug. You need a list of lists to force a column vector, and since that isn't really clean JSON, you wouldn't do that by default.
jsondecode('[[1],[2],[3]]')
ans = 3×1
1 2 3
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
It also assumes row-major matrix definitions (while the Matlab internal default is column-major).
A=zeros(2,2);
A(3)=1;
IsRowMajor = isequal(A,[0 0;1 0])
IsRowMajor = logical
0
IsColumnMajor = isequal(A,[0 1;0 0])
IsColumnMajor = logical
1
Paul
Paul el 15 de Abr. de 2025
  • MATLAB does not guarantee that the shape of an array is preserved. For example, a 1-by-N numeric vector is encoded as an array. If you call jsondecode, then MATLAB decodes the array as an N-by-1 vector.

Iniciar sesión para comentar.

Productos


Versión

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by