Useful links
1 Introduction.
This article contains further development of my previous article. Abstract nonsense (Category Theory) in mathematics is a common language for different branches of math which can be regarded as code reuse. Similarly number of my program components is being reduced by the time with simultaneous increasing of functionality. During 2007 - 2010 I developed SCADA systems. I find that OPC Foundation
is an excellent real-time technology. However a lot of AeroSpace companies does not understand this fact. I lot of people think that realtime control of an industrial enterprise is principally different from AeroSpace control. In result some companies use sockets instead OPC Foundation. This article contains a unified approach to real-time with examples of industrial control and AeroSpace. Recently I visited a seminar devoted to Simulink applications. The lector said following.
++++++++++
If you would like to develop a control system then our company shall help you.
++++++++++
It means that Simulink is quite clear for developers of Simulink only. The Simulink is very powerfull product with huge facilities. However this circumstance makes Simulink unvailable for a lot of people. I think that number Simulink components can be reduced such that Simulink shall support previous functionally but become more clear and available. I would like make more clear and available my own soft. I find that SCADA systems have relatively small number of components. However small number of components supplies a very reach functionality.
Laurence Chisholm Young wrote.
+++++++++++++++++++++
The view is sometimes expressed, and by quite eminent mathematicians, that the value and interest to be attached to piece of mathematics is directly related to amount of really hard work that goes into it. This is undoubtedly very true, but it must be borne in mind that this hard work is best done behind the scenes, and that much of it goes into putting the material in a form which is easily grasped. If a reader attaches value only to what he finds hard to follow he is liable to reach a very distorted picture of mathematics today. Similarly a pioneer in motoring may have judged of the power of the car by the amount of noise and dust that it raised, but this is hardly apt in our time. In mathematics, those whose criterion of the value of a result based on weighing the pages in which it is proved, or on measuring the time needed to grasp the proof with a stop-watch have experienced a number of shocks in modern times, as simple proofs were found for that that previously required long and involved arguments. The truth is that mathematics is really like a work of art: it requires infinite pains, but final result shows nothing of them, nothing to distract the viewer from deep understanding and insight that it brings to him.
+++++++++++++++++++++
Similarly I would like to develop "light" version of the Simulink.
2 Background
I find that OPC Foundation is an excellent an excellent real-time technology. However OPC Foundation is a commercial product and I cannot share it as OpenSource. Any developer can integrate OPC Foundation into my soft. To make my soft royalty free I developed proxy of the OPC Foundation. As well as OPC Foundation my proxy contains following ingredients:
- (Remote) events
- (Remote) data flow
The abstract nonsense pattern is used for real time. Following picture explains application of this pattern to real-time.
The Event object raises an event and the Event handler handles it. This example is empty. Following movie is not empty and some qualitative SCADA facilites of (events, data indication).
The Input object generates to time-dependent functions.
The Event object raises events. The Event handler object handles event, i.e. it takes information from Input and indicates it.
The Real-time domain contains following base types.
IEvent
this interface is implemented by any object which raises events. IEventHandler
this interface is implemented by any event handler. EventLink
link between event and event handler. Source (resp. target) of this link should implement IEvent
(resp. IEventHandler
interface).
There is many to many relationship between events and their handlers. Following code contains these base types.
public interface IEvent
{
event Action Event;
bool IsEnabled
{
get;
set;
}
}
public interface IEventHandler
{
void Add(IEvent ev);
void Remove(IEvent ev);
event Action<IEvent> OnAdd;
event Action<IEvent> OnRemove;
}
[Serializable()]
public class EventLink : CategoryArrow, IRemovableObject
{
#region Fields
IEvent target;
IEventHandler source;
#endregion
#region Ctor
public EventLink()
{
}
protected EventLink(SerializationInfo info, StreamingContext conext)
{
}
#endregion
#region Overriden Members
public override ICategoryObject Source
{
get
{
return source as ICategoryObject;
}
set
{
source = value.GetSource<IEventHandler>();
}
}
public override ICategoryObject Target
{
get
{
return target as ICategoryObject;
}
set
{
target = value.GetTarget<IEvent>();
source.Add(target);
}
}
#endregion
#region IRemovableObject Members
void IRemovableObject.RemoveObject()
{
if ((source == null) | (target == null))
{
return;
}
source.Remove(target);
source = null;
}
#endregion
}
Following text contains examples of this paradigm application.
3 Elementary Events
3.1 Forced event
A lot of engineering systems requires human-machine interface. The ForcedEvent
is designed for such facility. Following code explains business logic of this class.
[Serializable()]
public class ForcedEvent : CategoryObject, ISerializable, IEvent
{
#region Fields
event Action ev = () => { };
#endregion
#region IEvent Members
event Action IEvent.Event
{
add { ev += value; }
remove { ev -= value; }
}
#endregion
#region Public Members
public void Force()
{
ev();
}
#endregion
The Force
method raises event. Following movie explains how does forced event works.
3.2 Timer
Timer is an object such that raises distinguished by fixed interval events. .NET Framework supports several timers. The System.Windows.Forms.Timer
is intended for System.Windows.Forms
applications, the System.Windows.Threading.DispatcherTimer
. Universal software should support any type of timers. Following two interfaces are developed for this purpose:
public interface ITimer : IEvent
{
TimeSpan TimeSpan
{
get;
set;
}
}
public interface ITimerFactory
{
ITimer NewTimer
{
get;
}
}
The Windows Forms implementation of these interfaces is presented below.
public class Timer : ITimer, IDisposable
{
#region Fields
event Action ev = () => { };
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
bool isEnabled = false;
TimeSpan timeSpan = new TimeSpan();
#endregion
#region Ctor
internal Timer()
{
timer.Tick += (object sender, EventArgs e) =>
{
ev();
};
}
#endregion
#region ITimer Members
TimeSpan ITimer.TimeSpan
{
get
{
return timeSpan;
}
set
{
timeSpan = value;
if (value.TotalMilliseconds <= 0)
{
timer.Interval = 1;
return;
}
timer.Interval = (int)value.TotalMilliseconds;
}
}
#endregion
#region IEvent Members
event Action Interfaces.IEvent.Event
{
add { ev += value; }
remove { ev -= value; }
}
bool Interfaces.IEvent.IsEnabled
{
get
{
return isEnabled;
}
set
{
if (value == isEnabled)
{
return;
}
isEnabled = value;
timer.Enabled = value;
if (value)
{
timer.Start();
}
else
{
timer.Stop();
}
}
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
timer.Dispose();
}
#endregion
}
public class WindowsTimerFactory : ITimerFactory
{
#region Fields
public static WindowsTimerFactory Singleton = new WindowsTimerFactory();
#endregion
#region Ctor
private WindowsTimerFactory()
{
}
#endregion
#region ITimerFactory Members
ITimer ITimerFactory.NewTimer
{
get { return new Timer(); }
}
#endregion
}
3.3 "Direct sum" of events
3.3.1 Category Theory analogy
The abstract nonsense (Category Theory) in math supplies unified approach to different problems. This approach is very fruitful. Category theory promotes better understanding between mathematicians as well as design patterns in software development. For example Category Theory operates with abstract direct product which is presented below.
Above diagram means that there is a unique dashed arrow which makes above diagram commutative. If we have a category of sets, A (resp. B) is a fininte set on m (resp. n) elements then A×B is a set of mn elements. However in case of linear spaces if A is 1D space and B is a 2D space then A×B is a 3D space. Notion of the direct sum is obtained by inversion of arrows.
If we have a category of sets, A (resp. B) is a fininte set on m (resp. n) elements then A+B is a set of m + n elements. Furthermore, these categorical definitions give a new insight into our understanding of very first mathematical concepts, such as multiplication and addition
of natural numbers, intersection, product, and union of sets, and conjunction
and disjunction in mathematical logic. In particular they make addition dual
to multiplication and make disjoint union more natural than the ordinary one.
In simple words, everyone knows that, say,
a + b = b + a and ab = ba (for natural a and b),
but only category theory tells us that these equalities are special cases of a single
result! (Source of above citation)
Let us consider the "Direct sum" in 3D Graphics. Following two pictires represent complilcated motion of helicoper
So above helicopter contains 7 3D shapes (Fuselage, tail rotor and 5 blades of main rotor). The "Direct sum" of these shapes is whole helicopter as it is presented below.
The L 1 - L 5, Fuselage, Tail rotor are 3D shapes of blades 1-5, Fuselage, and Tail rotor respectively. The Full helicopter 3D is a "direct sum" of these shapes
since it is connected to other shapes by link. Otherwise five virtual cameras are linked to Full helicopter 3D by 5 arrows. If we connect 5 cameras with 7 3D shapes we need 5 * 7 =35 arrows. In result we have 7 + 5 = 12 arrows instead 5 * 7 = 35 ones.
3.3.2 "Direct sum" of events
As well as 3D graphics events also have direct sums. Following picture contains two elementary events Forced and Timer.
The Event collection object is a "direct sum" of these elementary events. The Event collection is an object of EventCollection
class. Following code explains how does it works
#region IEvent Members
event Action IEvent.Event
{
add
{
foreach (IEvent e in ev)
{
e.Event += value;
}
}
remove
{
foreach (IEvent e in ev)
{
e.Event -= value;
}
}
}
bool IEvent.IsEnabled
{
get
{
return isEnabled;
}
set
{
if (isEnabled == value)
{
return;
}
foreach (IEvent e in ev)
{
e.IsEnabled = value;
}
isEnabled = value;
}
}
#endregion
4 Events + Information flow
Any real-time system supports information flow. Some objects of real-time are simultaneously events and sources of information. For example any OPC Subscription provides data end raises an ItemChanged
event (See here). My framework also supports information flow. Here we consider objects which are elements of data flow and events.
4.1 Forced data event
4.1.1 Outlook
This object is intended for Human-Machine Interface. This object can be used in SCADA systems as well as in aviation simulators. The forced event data corresponds to the ForcedEventData
class which implements both IEvent
and IMeasurements
. So it raises events and it is a source of information. Following code explains logics of this class.
[Serializable()]
public class ForcedEventData : CategoryObject, ISerializable, IMeasurements,
IEvent, IAlias, IStarted
{
#region Fields
object[] data;
object[] initial;
event Action ev = () => { };
Action force = () => { };
#endregion
#region IEvent Members
event Action IEvent.Event
{
add { ev += value; }
remove { ev -= value; }
}
bool IEvent.IsEnabled
{
get
{
return isEnabled;
}
set
{
if (isEnabled == value)
{
return;
}
isEnabled = value;
force = value ? ev : () => { };
}
}
#endregion
#region Public Members
public object[] Data
{
get
{
return data;
}
set
{
data = value;
force();
}
}
#endregion
Above code means that changing of data raises an event. The forced event has following user interface.
This inteface enables us to set number of data elements and their types. Also this interface enables us chande initial and current values of data.
4.1.2 Application to control system
Let us consider the control system described by following equation.
where
- x - is an actual value of the physical parameter;
- y - is a required value of the physical parameter;
- c - is a constant;
Required value of the physical parameter is set by human. Following picture accomplished by video explains this phenomenon.
The Forced is an object of the ForcedEventData
type. Human uses this object for entering required value. The Timer is a timer event generator. The Event collection is a "direct sum" of Timer and Forced events. The Equation contains a differential equation of the control system. Properties of the Equation are presented below.
4.1.4 User interface
Above user interface is useful for design, but it is not convenient for working. Following user interface is appropriate for work.
Problems of user interface are explained below.
4.2 Remote events
4.2.1 Clients and Severs
Any advanced real-time system should support remote events. I have used the "A simplified non topic based Event Notification Server in wcf with multiple protocol support" as a prototype of remote events. Remote objects contains servers and clients. Servers raise events and supply information. Clients handle events and receive information. Following state chart diagram explains client server interpretability
The Register
method has following signature.
[ServiceContract(CallbackContract = typeof(IEvent))]
public interface IRegistration
{
[OperationContract]
string[] Register();
[OperationContract]
void UnRegister();
}
The Register
method returns array of strings. Odd elements of this array are names of parameters, even elements are corresponding type names. This remote method is called by client at initialization time. The sever calls the OnEvent
remote method.
[ServiceContract]
interface IEvent
{
[OperationContract(IsOneWay = true)]
void OnEvent(AlertData data);
}
[DataContract]
[KnownType(typeof(object[]))]
public class AlertData
{
[DataMember]
public object[] Data { get; set; }
}
Above code means that server transfers to client an array of object. Logic of this element is close to OPC server group.
Following picture shows example of server
Above picture means that output parameters of the Server are Formula_1 and Formula_2 of data Data, Server uses a IPC connection, and URL of the connection is "net.pipe://localhost/Data". Boolean parameter Formula_3 of Data is an event condition, i.e. an event is raised if and only if this parameter equals to true
. Properties of Data are presented below:
The data contains three output parameters.
N | Name | Type |
1 | Formula_1 | double |
2 | Formula_2 | string |
3 | Formula_3 | bool |
First and second parameters are exported by Server, third one is an event condition. Exported data is used by client as it is shown below.
Parameters of Client communication coincide with server ones. The Client preforms two functions:
- It provides data;
- It raises event.
Imported parameters Formula_1 and Formula_2 are used by DataConsumer. The DataConsumer is both:
- Consumer of data;
- Event handler.
The DataConsumer is connected to Client by the Data arrow as a consumer of data, and it is connected by the Event arrow as an event handler.
4.2.2 Start of multiple applications
Above sample implies that server and clients run as different applicatios as it is shown below:
There is interopreability of these applications. We need to start several instances of application with different files. However if files are zipped to single file, then drag and drop of single zip file to desktop automatically start multiple instances. I used the The Zip, GZip, BZip2 and Tar Implementation For .NET library for this purpose.
4.2.3 Application to temperature control
Let us consider a temperature control task. Temperature is controlled by heater which has "on" and "off" positions. This physical phenomenon is described by following ordinary equation.
where
- z is a heating parameter. (z = (heater is "off") ? 0 : d;
- a, b - positive real constant
s;
- T (resp. Texternal) controlled temperature (resp. external temperature).
Following picture represents a simulator of this phenomenon
The Temperature object supplies information from Hydrometeorological centre of Russia. Properties of this object are presented below.
.
Above component supplies following parameters.
N | Parameter name | Parameter type | Current value of parameter |
1 | Atmospheric pressure, mm mer. col | double | 760 |
2 | Temperature, °C | double | -1.8 |
3 | Temperature min., °C | double | - |
4 | Temperature max., °C | double | - |
5 | Comments | string | Snow strong weak |
6 | Wind direction | string | S |
7 | Wind speed, m/s | double | 2 |
1 | The general nebulosity value | double | 10 |
9 | Horizontal visibility, km | double | 4 |
This object is used instead an external thermometer only. The Control Signal is a remote client which supplies heating parameter. Both Timer and Control Signal are generators of events. The Event collection is a combination of these events. The Equation object supplies necessary differential equation.
The Recursive is intended for raise an analog of OPC DataChange event, proprerties of this object are presented below.
Parameter d of Recursive is threshold value, b is the event condition of the Server object. We use on–off control law which is expressed below.
Following pictrure represents controller.
There is feedback between controller and simulator represented in following table.
N | URL | Server side | Server object | Clent side | Client object |
1 | net.pipe://localhost/Sensor | Simulator | Sensor | Controller | Sensor |
2 | net.pipe://localhost/ControlSignal | Controller | Server | Simulator | Control Signal |
The Required object enables us to set required value of temperarue, it raises an OnChange
event. The Turn_off_control implements control law, properties of this object are presented below.
The All events object is a combination ("direct sum") of events raised by Sensor and Required, i.e All events is raised if the required or actual value of temperature is substantionally chanded. If value of controller output is changed then the Server raises remote event and exports value of the controller output.
Besides Inter-process communication all clients and servers support TCP and/or HTTP communication. So simulator of phenomenon and controller can be installed on different computers. Following picture illustrates TCP communication.
This sample requires additonal files.
5 User Intreface
Any SCADA system contains designer of user interface, following picture represents example of such designer.
However Visual Studio can be used as designer of SCADA user interface.
5.1 Windows Forms desinger
I used Open-source .NET SCADA framework as protototype. Following picture contains a user interface design for temperature control example.
Above picture means that edited object is event handler of the Timer, i.e edited object changes value if and only is Timer raises event. The Output of edited object is Reqursive_x parameter of the Sensor. Similar picture Following picture contains properties of a slider.
Above picture means that this slider enables us input Temperature of the Required. Both termometer and slider implement following interface:
public interface IScadaConsumer
{
IScadaInterface Scada
{
get;
set;
}
bool IsEnabled
{
get;
set;
}
}
where IScadaInterface
is abstract SCADA
public interface IScadaInterface
{
Dictionary<string, object> Inputs
{
get;
}
Dictionary<string, object> Outputs
{
get;
}
Dictionary<string, object> Constants
{
get;
}
List<string> Events
{
get;
}
Action<object> GetInput(string name);
Action<object[]> GetInput(string[] names);
Action<object> GetConstant(string name);
Func<object> GetOutput(string name);
Func<object[]> GetOutput(string[] names);
IEvent this[string name]
{
get;
}
T GetObject<T>(string name) where T : class;
bool IsEnabled
{
get;
set;
}
event Action OnStart;
event Action OnStop;
event Action<XmlDocument> OnCreateXml;
XmlDocument XmlDocument
{
get;
}
IErrorHandler ErrorHandler
{
get;
set;
}
void Refresh();
event Action OnRefresh;
}
Implementations of IScadaConsumer
for slider and thermometer are presented below.
#region Fields
string inputString;
Action<float> input;
#endregion
[DefaultValue("")]
[Editor(typeof(ListGridComboBox), typeof(UITypeEditor))]
[DataList("GetInputs")]
[TypeConverter(typeof(ListExpandableConverter))]
[Category("SCADA"), Description("Input name"), DisplayName("Input")]
public string Output
{
get
{
return inputString;
}
set
{
inputString = value;
}
}
#region IScadaConsumer Members
IScadaInterface IScadaConsumer.Scada
{
get
{
return scada;
}
set
{
if (value == null)
{
return;
}
scada = value;
input = GetFloatInput(scada, inputString);
}
}
bool IScadaConsumer.IsEnabled
{
get
{
return isEnabled;
}
set
{
if (isEnabled == value)
{
return;
}
isEnabled = value;
if (value)
{
this.ValueChanged += Slider_ValueChanged;
}
else
{
this.ValueChanged += Slider_ValueChanged;
}
}
}
#endregion
#region Public Membres
public static Action<float> GetFloatInput(this IScadaInterface scada, string name)
{
Action<object> action = scada.GetInput(name);
return GetFloatInput(action, scada.Inputs[name]);
}
#endregion
#region Private Members
static Action<float> GetFloatInput(Action<object> action, object type)
{
Type t = type.DetectType();
if (t.Equals(typeof(float)))
{
return (float x) => { action(x); };
}
else
{
return (float x) =>
{
double a = (double)x;
action(a);
};
}
}
void Slider_ValueChanged(object sender, EventArgs e)
{
input(_val);
}
#endregion
#region Scada Input Fields
string eventString;
string outputString;
Func<float> output;
IScadaInterface scada;
IEvent eventObject;
bool isEnabled;
#endregion
#region Public Members
[DefaultValue("")]
[Editor(typeof(ListGridComboBox), typeof(UITypeEditor))]
[DataList("GetEvents")]
[TypeConverter(typeof(ListExpandableConverter))]
[Category("SCADA"), Description("Event name"), DisplayName("Event")]
public string Event
{
get
{
return eventString;
}
set
{
eventString = value;
}
}
[DefaultValue("")]
[Editor(typeof(ListGridComboBox), typeof(UITypeEditor))]
[DataList("GetOutputs")]
[TypeConverter(typeof(ListExpandableConverter))]
[Category("SCADA"), Description("Output name"), DisplayName("Output")]
public string Output
{
get
{
return outputString;
}
set
{
outputString = value;
}
}
#endregion
#region IScadaConsumer Members
IScadaInterface IScadaConsumer.Scada
{
get
{
return scada;
}
set
{
if (value == null)
{
return;
}
scada = value;
eventObject = scada[eventString];
output = GetFloatOutput(scada, outputString);
}
}
bool IScadaConsumer.IsEnabled
{
get
{
return isEnabled;
}
set
{
if (isEnabled == value)
{
return;
}
isEnabled = value;
if (value)
{
eventObject.Event += Set;
}
else
{
eventObject.Event -= Set;
}
}
}
#endregion
#region Private Members
void Set()
{
Set(output());
}
public void Set(float val)
{
if (base.Enabled)
{
float temp = _val;
if (val > _max) val = _max;
if (val < _min) val = _min;
_val = val;
if (temp != _val)
{
OnValueChanged();
base.Invalidate();
base.Update();
}
}
}
static Func<float> GetFloatOutput(IScadaInterface scada, string name)
{
Func<object> f = scada.GetOutput(name);
return GetFloatOutput(f, scada.Outputs[name]);
}
static Func<float> GetFloatOutput(Func<object> func, object type)
{
Type t = type.DetectType();
if (t.Equals(typeof(float)))
{
return () => { return (float)func(); };
}
else
{
return () =>
{
double a = (double)func();
return (float)a;
};
}
}
#endregion
Interpretability of SCADA with Windows Forms is implemented by recursion as it is presented below.
#region Public Members
public static void RecursiveAction(this Control control, Action<Control> action)
{
action(control);
foreach (Control c in control.Controls)
{
c.RecursiveAction(action);
}
}
public static void Set(this Control control, IScadaInterface scada)
{
control.SetPrivate(scada);
scada.OnRefresh += () => { control.SetPrivate(scada); };
scada.OnStart += () => { control.SetScadaEnabled(true); };
scada.OnStop += () => { control.SetScadaEnabled(false); };
}
public static void SetScadaEnabled(this Control control, bool isEnabled)
{
control.RecursiveAction((Control c) =>
{
if (c is IScadaConsumer)
{
(c as IScadaConsumer).IsEnabled = isEnabled;
}
});
}
#endregion
#region Private & Internal Members
private static void SetPrivate(this Control control, IScadaInterface scada)
{
control.RecursiveAction((Control c) =>
{
if (c is IScadaConsumer)
{
(c as IScadaConsumer).Scada = scada;
}
});
}
#endregion
Following picture supplied with video shows temperature control example.
Above picture represents two applications:
- Simulator of physical phenomenon;
- Controller.
Start includes following two steps.
1. Start of simulator in design mode. User should start Aviation.exe
, and open sensor.cfa
file from ipc_control.zip 144 KB
2. Start controller application.
5.2 WPF user interface
I think that WPF technology is more close to SCADA than Windows Forms. The System.Windows.Forms
implies common loop of events. However any WPF UI element has its own thread and so its own dispatcher. So we can associate different WPF UI elements with different events. Some SCADA systems do not imply user interface because they supply control without HMI. Different types of SCADA imply different types of timers. If we use WPF we should replace Windows Forms Timer by following timer.
public class Timer : ITimer, IDisposable
{
#region Fields
event Action ev = () => { };
DispatcherTimer timer = new DispatcherTimer();
bool isEnabled = false;
TimeSpan timeSpan = new TimeSpan();
#endregion
#region Ctor
internal Timer()
{
timer.Tick += (object sender, EventArgs e) =>
{
ev();
};
}
#endregion
#region ITimer Members
TimeSpan ITimer.TimeSpan
{
get
{
return timeSpan;
}
set
{
timeSpan = value;
timer.Interval = value;
}
}
#endregion
#region IEvent Members
event Action Interfaces.IEvent.Event
{
add { ev += value; }
remove { ev -= value; }
}
bool Interfaces.IEvent.IsEnabled
{
get
{
return isEnabled;
}
set
{
if (value == isEnabled)
{
return;
}
isEnabled = value;
timer.IsEnabled = value;
if (value)
{
timer.Start();
}
else
{
timer.Stop();
}
}
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
try
{
if (timer != null)
{
timer.Stop();
}
}
catch (Exception)
{
}
timer = null;
}
#endregion
}
5.4.1 Flight simulator
Any flight simulator is in fact a SCADA system accomplished by advanced 3D graphics, audio support and special devices. I think that SCADA technologies (for example OPC) would be very useful for flight simulators. I wrote an article devoted to audio support with its application to flight simulators. Following picture explains this task.
As well as temperature control example this example uses meteorological component. So this component also provides angle of wind direction. Usage of wind velocity and wind direction is twofold. First of all these parameters are used in ATIS audio message. Moreover these parameters are used in motion equations. Times of audio messages depend on simulated aircraft motion. ATIS message time depends on distance to airport. Height (resp. velocity) messages are being played in transition of height (resp. velocity) times. Here is a description of this task in details. Following picture (with video + audio)
shows virtual cameras.
Installation of audio files includes following steps.
Step 1. Unpacking audio archive to any directory.
Step 2. Setting directory of unpacked files by following way
We would like to develop user interface for this task. I used Circular gauge custom control for Silverlight 3 and WPF for indication of altitude and velocity. The CircularGaugeControl
is extended by following way.
[TemplatePart(Name = "LayoutRoot", Type = typeof(Grid))]
[TemplatePart(Name = "Pointer", Type = typeof(Path))]
[TemplatePart(Name = "RangeIndicatorLight", Type = typeof(Ellipse))]
[TemplatePart(Name = "PointerCap", Type = typeof(Ellipse))]
public class ScadaCircularGaugeControl : CircularGauge.CircularGaugeControl, IScadaConsumer
{
#region Fields
#region Scada Input Fields
Func<double> output;
IScadaInterface scada;
IEvent eventObject;
bool isEnabled;
#endregion
#region Ctor
public ScadaCircularGaugeControl()
{
Unloaded += (object sender, RoutedEventArgs e) =>
{ (this as IScadaConsumer).IsEnabled = false; };
}
#endregion
#endregion
#region IScadaConsumer Members
IScadaInterface IScadaConsumer.Scada
{
get
{
return scada;
}
set
{
if (value == null)
{
return;
}
scada = value;
if (eventObject != null)
{
if (isEnabled)
{
eventObject.Event -= Set;
}
}
eventObject = scada[Event];
output = scada.GetDoubleOutput(Output);
}
}
bool IScadaConsumer.IsEnabled
{
get
{
return isEnabled;
}
set
{
if (isEnabled == value)
{
return;
}
isEnabled = value;
if (value)
{
eventObject.Event += Set;
}
else
{
eventObject.Event -= Set;
}
}
}
#endregion
#region Public Members
[Browsable(true)]
[TypeConverter(typeof(EventConverter))]
[Category("SCADA"), Description("Event name"), DisplayName("Event")]
public string Event
{
get;
set;
}
[Browsable(true)]
[TypeConverter(typeof(OutputRealConverter))]
[Category("SCADA"), Description("Output name"), DisplayName("Output")]
public string Output
{
get;
set;
}
#endregion
#region Private Methods
void Set()
{
base.CurrentValue = output();
}
#endregion
}
Editor of properties of this component is presented below.
Properties of this control are similar to termometer ones. WPF SCADA contains special user control (UserControlCamera)
for virtual 3D camera. Propreties of this control are presented below.
Full application accomplished with video + audio is presented below.
The sounds
directory from sounds.zip archive should be copied to the location of Scada.WPF.Sound.Sample.exe
file.
5.4.2 Real-time satellite 3D vizualization
I wrote an article devoted to determination of orbits of artificial satellites. However we can extend functionality by real-time visualization. We would like use parameters of present time satellites an show different pictures of Earth from virtual satellites. Similar task is described in my previous article. However early I did not consider real-time. Now this task is accomplished by following features:
The NORAD Two-Line Element Sets web site supplies Keplerian elements for most satellites in low-earth orbit. I used HTML to XAML converter for development of the wrapper. Following pictures shows the website and its wrapper.
Web site
WPF Wrapper
I also used Celestia. Real-time 3D visualization of space, I converted some classes from C++ to C#. Moreover I developed object oriented wrapper of Empirical, global model of the Earth's atmosphere from ground to space (NRLMSISE-00). In result we have following picture.
The Timer is a timer for real-time. The NASA Image object is intended for textures. We can enter any URL from NASA Earth Observations web site.
The Celestrak is a wrapper NORAD Two-Line Element Sets website.
So we have business logic, now we wold like develop user interface. We use UserControlCamera control for visualization of camera. We also use GridTextOutput
and UserControlChartGroup
for output of digital parameters. This components are presented below.
The UserControlWebPage
is used for change texture
The UserControlCelestrak
is used for selection of the satellite.
In result we have following application.
Points of Interest
One man said to me: "I know more than you because I 50 years worked at single company." I answered: "I know more than you because I worked at lot of companies.