Using MATLAB Structures in C# with Builder NE
Guest blogger Peter Webb returns with another in an occasional series of postings about application deployment.
Contents
Structures Simplify Your Interfaces
To demonstrate how to use structures in an C# application deployed with Builder NE, I've written a MATLAB function to compute the time it takes a planet to orbit around the sun. computeOrbit needs three pieces of information about a planet: the planet's name, its mass, and its distance from the sun. It returns the planet's name and the orbital period. By grouping the input and output data into structures, I can give computeOrbit a very simple interface:
function orbit = computeOrbit(planet)
To compute the length of the Martian year, pass in this MATLAB structure:
planet.name = 'Mars'; planet.mass = 6.4185e+023; planet.smAxis = 2.2792e+011
computeOrbit returns a structure with two fields:
name: 'Mars' period: 686.88
And because it's a MATLAB function, if you give computeOrbit a vector of planets, it returns a vector of orbits. I'd like my C# interface to computeOrbit to take and return the same kind of structures. For example, if you create a structure array planets with data for the four inner planets, computeOrbit will return a structure array:
>> [planets(1:4).name] = deal('Mercury', 'Venus', 'Earth', 'Mars'); >> [planets.mass] = deal(3.3020e+023, 4.8685e+024, 5.9736e+024, ... 6.4185e+023); >> [planets.smAxis] = deal(5.7910e+010, 1.0821e+011, 1.4960e+011, ... 2.2792e+011); >> orbits = computeOrbit(planets); >> orbits(3)
ans =
name: 'Earth' period: 365.2641
Declaring MATLAB-Compatible Structures in C#
The C# interface needs two structures: Planet and Orbit. To prevent conflict with similarly named types in other components, I've placed these types in a C# namespace, Uranometria (derived from Greek, it means "measuring the sky"). For convenience, I also provided the C# Planet structure with a constructor, but this is not strictly necessary.
namespace Uranometria { public struct Planet { public string name; public double mass; public double smAxis; public Planet(string n, double m, double sma) { name = n; mass = m; smAxis = sma; } }
public struct Orbit { public string name; public double period; } }
Builder NE will only automatically marshall structure data between identical structures: the C# and MATLAB field names must be exactly the same and the corresponding field data types must be compatible. Here, compatible means conversion from one type to the other occurs without loss of information. Compatibility is an ordered relationship: conversion from integer to double preserves information, but conversion from double to integer might not. C#'s System.Int32 is therefore compatible with MATLAB's double, but not vice-versa.
Use the Orbit and Planet types to define the C# signature of the C# interface function computeOrbit:
public interface IOrbit { Uranometria.Orbit[] computeOrbit(Uranometria.Planet[] p); }
Since the MATLAB function computeOrbit takes and returns structure arrays, the C# computeOrbit interface function specifies arrays of structures for both the input and output parameters.
Passing Structures between MATLAB and C#
In C#, declare an array of Planet structures:
Uranometria.Planet[] planet = new Uranometria.Planet[4];
I've qualified the type Planet with its namespace because I think it makes the type name clearer. But you could remove the qualification with a using directive.
Next, add some data (here, the data for Mercury) to the the array, using the convenience constructor:
planet[0] = new Uranometria.Planet("Mercury", 3.3020e+023, 5.7910e+010);
Create an instance of the OrbitalMechanics component. This initializes the compenent and starts the MCR.
IOrbit o = new Uranometria.OrbitalMechanicsIOrbit();
Call the computeOrbit MATLAB function, passing it the array of planets:
Uranometria.Orbit[] orbit = o.computeOrbit(planet);
computeOrbit returns an array of Orbit data. Iterate over the array, printing the name and period of each planetary orbit.
foreach (var p in orbit) System.Console.WriteLine("{0,-7} {1,6:f} days", p.name, p.period);
Building and Running the Example
First, download the example code from MATLAB Central. The download consists of the computeOrbit MATLAB function and a Visual Studio project that builds an application which calls computeOrbit. To build the example, you'll need to:
The file ReadmeStructures.txt contains detailed instructions.
The downloaded files compile into Orrery.exe, which computes the orbital period of the four inner planets. Run from the DOS command line (make sure you've got your runtime environment set up correctly), it produces a four-row table:
Planet Period --------------- Mercury 87.97 days Venus 224.70 days Earth 365.26 days Mars 686.88 days
To compute the orbits of other planets, add more data to the array of Planet structures in Orrery.cs and rebuild the C# main application. There's no need to recompile the computeOrbit function.
How Does Your Code Use Structures?
Let me know about how your C# programs use MATLAB structures. Is this how you'd expect to pass structures between C# and MATLAB programs? Let me know here.
- 类别:
- Deployment