Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Design of tool for visual exploration

Asked by per isakson on 19 Sep 2012

Questions

  1. I assume that there is no way to let an assignment, a=qty;, where qty is an instance of a value class, call some user code. (Something like subsref.) Am I correct?
  2. A value class to represent a time series will provide better perfomance and a more robust code than would a handle class. Am I correct?
  3. The design I outline below, does it look sound?

Background

Energy efficient operation of buildings. The building automation system, BAS, provides plenty of time series data: temperatures, power, control signals, etc. Building simulation programs provides similar time series. A building can deliver approximately 1GB per year of data - more in the future.

Some ten year ago I settled on a Matlab structure that contains several hundreds of the time series together with some metadata. Over the years I built a number of visual tools that use my data structure. These tools are used by experts in building operation. The full focus of the user shall be on the behavior of the building. Simple interface and fast response are both important. The tools have been surprisingly well received.

There is a shortcoming that is severe especially when exploring simulation results. Now, in a first step I compile one data structure and in a second step I do the visual exploration. What happens is that when studying a certain behavior in one building I want to compare to the behavior of a different building or simulation and that data are not in the current structure - that irks.

My goal is to make a visual tool, which provides an immense of time series data at the finger tips of the user.

So far

I have concluded based on tests that

  1. it is possible to read data from files on-the-fly and still deliver acceptable response times. A home-brewed system based on fwrite/fread+memmapfile(?), matfile, high level HDF5 and low level NetCDF4 are all possible alternatives. (Soon enough we will have fast solid-state-disks.)
  2. I shall trust Windows' file-cache and Matlabs copy-on-write (/lazy-copy).
  3. I shall try to limit Matlabs memory foot-print. The file cache makes good use of memory.

It is highly possible that several tools simultaneously use a certain time series. In this case it is crucial that there is only one copy of the underlying numerical array in Matlabs memory. Thus, each tool must not retrieve the data from the data file. When all tools have cleared their references to the time series it shall be cleared from the Matlab memory.

Deep under the hood Matlab has information on how variables refer to numerical arrays, but I use plain documented Matlab.

Now I'm experimenting with a little system to study allocation and release of memory. It consists of

  1. SharedQty - A singleton handle class, which keeps a register of QtyX instances in use.
  2. QtyX - A time series value class. Creation of QtyX instancies should only be done by SharedQty
  3. PhysicalMemoryInUse - function
  4. pass_QtyX_as_argument - function

I have ran several scripts like the one below to see how memory is allocated and released. So far it seems to work as expected.

mem(1)  = PhysicalMemoryInUse();
q11     = SharedQty.getQty( 'Qty1001' );        % memory allocated
mem(2)  = PhysicalMemoryInUse();
q21     = SharedQty.getQty( 'Qty1002' );        % memory allocated
mem(3)  = PhysicalMemoryInUse();
mem(4)  = pass_QtyX_as_argument( q11 );
mem(5)  = pass_QtyX_as_argument( q21 );
q12     = copy( q11 );
mem(6)  = PhysicalMemoryInUse();
q22     = copy( q21 );
mem(7)  = PhysicalMemoryInUse();
clear( 'q12' )
mem(8)  = PhysicalMemoryInUse();
clear( 'q22' )
mem(9)  = PhysicalMemoryInUse();
clear( 'q11' )                                  % memory released
mem(10) = PhysicalMemoryInUse();               
clear( 'q21' )                                  % memory released
mem(11) = PhysicalMemoryInUse();

.

--- listings ---

classdef    ( Sealed ) SharedQty < handle    
%   Singleton pattern
    properties  ( Access = private )
        next_id     = 1;
        QtyBuffer
    end
    methods ( Access = private )        
        function  this = SharedQty()                      
        end
    end
    methods ( Static = true, Access = public ) 
        function    id = unique_id()
            this            = SharedQty.Instance; 
            id              = this.next_id;
            this.next_id    = this.next_id + 1; 
        end
        function    qty = getQty( name )
            this = SharedQty.Instance; 
            if not( isempty( this.QtyBuffer ) )
                [ ism, ixm ] = ismember( name, { this.QtyBuffer.DataName } );
            else
                ism = false;
            end
            if ism
                qty = copy( this.QtyBuffer(ixm).Object );
            else                
                qty = QtyX( name );
            end
        end
        function    register( qty )
            this = SharedQty.Instance; 
%           The property, Cleanup, of the instance of QtyX, which is kept in 
%           SharedQty, shall not have a value. The property itself cannot be 
%           removed              
            qty.Cleanup = [];   
            if not( isempty( this.QtyBuffer ) )
                [ ism, ixm ] = ismember( qty.DataName, {this.QtyBuffer.DataName} );
                if ism 
                    this.QtyBuffer(ixm).ID_list ...
                        = [ this.QtyBuffer(ixm).ID_list, qty.ID ];
                else
                    this.QtyBuffer(end+1).ID_list   = qty.ID;
                    this.QtyBuffer(end  ).DataName  = qty.DataName;
                    this.QtyBuffer(end  ).Object    = qty;
                end
            else
                this.QtyBuffer.ID_list   = qty.ID;
                this.QtyBuffer.DataName  = qty.DataName;
                this.QtyBuffer.Object    = qty;
            end
        end
        function    deregister( id, name )
            this = SharedQty.Instance;
            [ ism, loc ] = ismember( name, { this.QtyBuffer.DataName } );
            if ism && sum(loc)==1
                this.QtyBuffer(ism).ID_list ...
                    = setdiff( this.QtyBuffer(ism).ID_list, id );
                if isempty( this.QtyBuffer( ism ).ID_list )
                    this.QtyBuffer( ism ) = [];
                end
            end
        end
    end
    methods ( Static = true, Access = public )                  
        function    this = Instance()
            persistent  instance
            if isempty( instance ) || not( isvalid( instance ) )
                instance = SharedQty;
            end
            this = instance;
        end
    end
end   

.

    classdef    QtyX  
        properties
            val
            Cleanup
            ID  
            DataName   
        end
        properties ( Constant = true )
            Length = 1e8;
        end
        methods
            function    this = QtyX( name )
                this.val        = ones( this.Length, 1 ); % mimics file data
                this.ID         = SharedQty.unique_id;
                this.DataName   = name;
                SharedQty.register( this );
                this.Cleanup = onCleanup  ...
                            ( @() SharedQty.deregister( this.ID, this.DataName ) );
            end
            function    qty = copy( this )
                qty         = this;
                qty.ID      = SharedQty.unique_id;
                qty.Cleanup = onCleanup                                         ...
                            ( @() SharedQty.deregister( qty.ID, qty.DataName )  );
            end
            function    qty = set_unique_ID( qty )
                qty.ID      = SharedQty.unique_id;
                qty.Cleanup = onCleanup                                         ...
                            ( @() SharedQty.deregister( qty.ID, qty.DataName )  );
            end
        end
    end

.

function    mem = PhysicalMemoryInUse()
    pause( 0.5 )
    [ ~, system_view ]  = memory;
    mem = system_view.PhysicalMemory.Total      ...
        - system_view.PhysicalMemory.Available  ;    
end

.

function    mem = pass_QtyX_as_argument( qty )
    qty = set_unique_ID( qty );            
    mem = PhysicalMemoryInUse();
    variable_not_used( qty )
end

0 Comments

per isakson

Products

No products are associated with this question.

0 Answers

Contact us