Matlab中一个结构体在另一个结构体中的大小(R2010a 64位Linux)

3

我正在使用Matlab API,将数据从专有格式加载到一系列结构中。以下是加载文件后数据集的示例:

>>fieldnames(data(1))

ans =

'Grid_Point_ID'
'Grid_Point_Latitude'
'Grid_Point_Longitude'
'Grid_Point_Altitude'
'Grid_Point_Mask'
'BT_Data'

>> data(1).BT_Data

ans =

BT_Data: [1x66 struct]

>> fieldnames(data(1).BT_Data(1))

ans =

'Flags'
'BT_Value_Real'
'BT_Value_Imag'
'Pixel_Radiometric_Accuracy'
'Incidence_Angle'
'Azimuth_Angle'
'Faraday_Rotation_Angle'
'Geometric_Rotation_Angle'
'Snapshot_ID_of_Pixel'
'Footprint_Axis1'
'Footprint_Axis2'

我希望能循环遍历所有的data(i).BT_Data(j)。我已经成功获取了data的长度,但是我无法获取BT_Data的大小/长度(每个data(i)都不同):

>> length(data(1).BT_Data)

ans =

 1

>> size(data(1).BT_Data)

ans =

 1     1
我的期望结果是ans=66(或者对于size()的等效数组)。
我对数据结构格式并不十分熟悉,这可能是我遇到困难的原因之一。但是length(data)运行良好,所以我很困惑为什么它不能在BT_Data上工作(我也尝试过BT_Data(:))。
我能找到的最相关的先前答案是1757250,但我无法让它起作用(我认为它不适用于此)。感谢您提供的任何见解。
------编辑------
以下是更多关于如何使用API的见解:

>> system('ln -sf /opt/rwapi-matlab/lib/rwapi/smos/config/xml_rw_api.usr_conf.xml .');
setenv('XML_RW_API_HOME','/opt/rwapi-matlab/lib/rwapi');
path(path,'/opt/rwapi-matlab');

>> prod = RWAPI.product('SM_OPEB_MIR_SCLF1C_20110202T013659_20110202T014642_346_060_1')

Array SMOS Matlab Interface version 1.4
(c) 2010 Array Systems Computing Inc. of Canada (http://www.array.ca)
Distribution or modification of this software requires written permission from Array

prod =

RWAPI.product handle
Package: RWAPI

Properties:
     filename: 'SM_OPEB_MIR_SCLF1C_20110202T013659_20110202T014642_346_060_1'
       header: [1x1 struct]
xml_datablock: []

Methods, Events, Superclasses

>> data = prod.dataset(2)

data =

RWAPI.dataset handle with no properties. Package: RWAPI

Methods, Events, Superclasses

>> data(1)

ans =

       Grid_Point_ID: 251721
 Grid_Point_Latitude: 25.5000
Grid_Point_Longitude: -102.2590
 Grid_Point_Altitude: 1.4714e+03
     Grid_Point_Mask: 2
             BT_Data: [1x66 struct]

>> data(1).BT_Data

ans =

BT_Data: [1x66 struct]

>> data(1).BT_Data(1)

ans =

                     Flags: 6229
             BT_Value_Real: 262.5275
             BT_Value_Imag: 0
Pixel_Radiometric_Accuracy: 6160
           Incidence_Angle: 31966
             Azimuth_Angle: 10299
    Faraday_Rotation_Angle: 65277
  Geometric_Rotation_Angle: 58605
      Snapshot_ID_of_Pixel: 65752530
           Footprint_Axis1: 19649
           Footprint_Axis2: 14625

>> whos
Name Size Bytes Class Attributes

ans 1x1 1 logical
data 1x19091 112 RWAPI.dataset
prod 1x2 112 RWAPI.product

3个回答

2

我找到了一个解决办法,虽然并不是特别令人满意:

>> a = data(1).BT_Data

a =

BT_Data: [1x66 struct]

>> length(a.BT_Data)

ans =

66

我现在将其标记为答案,因为我怀疑没有其他“正常”的方法来解决它。

安德鲁的回答真正抓住了问题所在(以及为什么这个解决方法有效)。


2
如果这是RWAPI的subsref方法中的奇怪现象,那么这就有意义了。当您执行像data(1).BT_Data(3)这样的引用链时,所有步骤 -“(1)”,“.BT_Data”和“(3)”-都会传递给数据的subsref()方法,并且可以自由地处理或错误处理它们。通过在中间变量中捕获较短引用的结果,您可以获得一个结构体,并调用正常的索引和length()函数。 - Andrew Janke

2

好的,我很怀疑这是RWAPI类中覆盖的subsref方法的奇异性。通过定义一个稍微有些病态的subsref类,我能够复现你观察到的所有行为。

classdef stupidref
    %STUPIDREF Reproduce odd indexing behavior that jpatton saw. Buggy.
    properties
        BT_Data = repmat(struct('foo',42, 'bar',42), [1 66]);
    end
    methods
        function B = subsref(A,S)
            s = S(1);
            subs = s.subs;
            chain = S(2:end);

            switch s.type
                case '()'
                    B = builtin( 'subsref', A, s );
                    if ~isempty(chain)
                        B = subsref(B, chain);
                    end

                case '.'
                    % Non-standard behavior!
                    if ~isempty(chain) && isequal(chain(1).type, '()')
                        B = subsref(A.(s.subs), chain);
                    else
                        B = struct(s.subs, A.(s.subs));
                    end
            end
        end
    end
end

这与 data(1).BT_Datafieldnames(data(1).BT_Data(1)) 之间的奇怪差异以及反复添加“.BT_Data”的选项卡完成相一致。

>> data = stupidref;
>> data(1).BT_Data
ans = 
    BT_Data: [1x66 struct]
>> fieldnames(data(1).BT_Data)
ans = 
    'BT_Data'
>> fieldnames(data(1).BT_Data(1))
ans = 
    'foo'
    'bar'
>> length(data(1).BT_Data)
ans =
     1
>> data(1).BT_Data.BT_Data.BT_Data.BT_Data.BT_Data.BT_Data % produced by tab-completion
ans = 
    BT_Data: [1x66 struct]
>> 

你的解决方法很好 - 一旦你调用 a = data(1).BT_Data,你就得到了一个普通的结构体,并且非标准的 subsref 就被排除在外了。你可以用 getfield 在一行代码中实现相同的效果。

>> btdata = getfield(data(1).BT_Data, 'BT_Data')
btdata = 
1x66 struct array with fields:
    foo
    bar

我建议向RWAPI库的作者报告这个可能的bug。
你可以直接将这段代码编辑到你自己的解决方案中,它并不是一个答案,而是支持诊断。

1
+1:太好了!看起来你找到了关键证据。如果RWAPI库的作者们来到这个帖子并看到一个名为“stupidref”的类,复制了他们的类,我会很想做一只墙上的苍蝇!=D - gnovice
哇,太棒了!这真的超出了我的能力范围(我以前从未使用过Matlab进行除数组/矩阵等之外的操作),但是在我尝试更好地理解结构体/对象时,这将是一个很好的参考。确实值得一加(我现在可以这样做了!)。 - jpatton
谢谢大家!@Jpatton,希望你在Matlab职业生涯中不必处理太多这类事情。 - Andrew Janke

1

您的一些结果似乎是矛盾的。首先,如果字段 BT_Data 包含一个 1x66 的结构数组,我会期望看到类似这样的输出:

>> data(1).BT_Data

ans =

1x66 struct array with fields:
     Flags
     ...    %# etc.

如果你看到这个:

>> data(1).BT_Data

ans =

BT_Data: [1x66 struct]

根据我的理解,BT_Data 实际上是一个 1x1 的结构体,其中包含一个名为 BT_Data 的字段,而该字段又包含一个 1x66 的结构体数组。这可以解释当你获取第一个 BT_Data 的长度和大小时看到的情况(即一个 1x1 的结构体)。如果是这种情况,你应该会得到以下结果:

>> size(data(1).BT_Data.BT_Data)

ans =

     1     66

然而,这仍然无法解释您执行以下操作时看到的输出:
fieldnames(data(1).BT_Data(1))

这让我感到困惑。你可能需要检查一下BT_Data是否实际上是一个结构体,而不是其他类型的对象,因为这些对象可能具有不同的索引和显示行为,可以通过执行以下操作来检查:

isstruct(data(1).BT_Data)

如果BT_Data是一个结构,则应该返回1


2
这几乎听起来像是一个损坏的结构体。这个专有的API是否使用MEX文件来处理Matlab的内部数据结构? - Andrew Janke
1
在加载数据后,whos的输出是什么?builtin('isstruct', data(1).BT_Data)呢?(以防万一,用户定义的类可以覆盖isstruct()来伪装成结构体,而builtin()则绕过了这一点。) - Andrew Janke
1
@jpatton:不要担心我提到的通知问题,你没有做错任何事情。当有人在你的帖子上发表评论时,你会通过SO收到通知。安德鲁在我的回答中留下的评论只是通知我,因为它们中没有“@jpatton”,我只是想让安德鲁知道,因为我认为它们对你很有帮助。 - gnovice
2
@jpatton:是的。这看起来像是RWAPI.product和RWAPI.dataset类中的问题。它们不是结构体(损坏或其他),而是对象,它们可能覆盖了subsref并执行非标准索引,就像gnovice建议的那样,并且可能处理“链接”不当。这与您下面的解决方法一致,我认为tab-completion行为也是如此。在我看来,这很可能是RWAPI中的一个错误。 - Andrew Janke
2
@jpatton,@gnovice:是的,使用带有虚假subsref的对象得到了一个相当完整的重现。由于代码太长了不能在评论中发布,所以我在一个单独的回答下面发布了代码。 - Andrew Janke
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接