Initial Conditions

Sep 11, 2008 16 Replies

Hi,



I am designing a fairly simple embedded system. It is probably similar to a million other embedded systems, but I'm very new to the field and am struggling with the problem of "initial conditions."



The system works like so:


1) All the inputs are predefined. Each one can be thought of as just a single floating point number. An example of an input might be the voltage measured on an A-to-D pin, or it could be something else. As far as the user is concerned, it's just a number that is magically pumped into the system and constantly changing.


2) All the outputs are also predefined. They are also represented by a single floating point number. That number might become an analog voltage on some output pin, or it might become the frequency of an output square wave, or something else entirely. Each output does something different.


3) All of the "blocks" between inputs and outputs are defined by the user. These blocks can be connected to inputs and outputs in any way that the user chooses. Each one of these blocks performs some small function, for example, an "ADDER" block has two inputs and one output and the value of the output is just (input_a + input_b).

So it's a system that allows a user to build a certain behavior, as far as how inputs are processed and eventually propagated to the outputs.



Ok, here's the catch. The system allows "loops" in the graph. So you could have the output of one block feeding back to the input of another block that is a long way "upstream" (meaning towards the inputs). In fact, this kind of feedback loop is necessary for certain kinds of processing.



These loops make it difficult (maybe impossible?) to ensure that a particular block has been safely initialized, meaning that its output can be trusted for use as input to something else. My first attempt was to make it a rule that a given block is considered uninitialized until all of its inputs had received valid data. But the loop case breaks this model, obviously.



So my next approach was to provide safe initial values for every block in the system. But that also turns out to be nearly impossible, without some human intervention from the user. For example, you can't just initialize the output of every block to zero, because the next block in the chain might be a block that performs the function (input_a / input_b), and this would cause a +INFINITY to be the output of that block. If that +INFINITY is part of one of these feedback loops, then the whole loop will probably become completely invalid. But it only reached that state because of a poor choice of initial conditions. Under normal operating conditions, that "input_b" would never be zero. But there's no way to really know that unless you have some prior knowledge about what the system does and what the "reasonable" ranges of all the inputs will be.



So how is this problem of initial conditions normally solved? It seems to me that the problem would be encountered in any sort of simulation tool that involves a connected graph like this. So any modelling systems like Simulink, or any kind of circuit design tool like PSpice, or any graphical flowcharting tool, etc... would have this same issue. Is there some standard way of dealing with this?


In case my generic description is confusing, here is a specific example of what a user might do that creates a problem.


+-----------------------------------+ | +----------+ | +-->|A MATH | |
+---------+ | BLOCK | +----------+ | | INPUT 1 |------>|B (A/B) |---->|A MATH | |
+---------+ +----------+ | BLOCK | | +--------+ +------------------->|B (A+B) |---+--->| OUTPUT |
+---------+ | +----------+ +--------+ | INPUT 2 |---+
+---------+


Thanks!



Pat


After A/D conversion your signals are digital. These are by definition time discrete (i.e. not time continuous). Hence they cannot be constantly changing. There must be some clock/sample mechanism which determines the conversion rate: there is no change in between.

W.r.t. clock/sampling you must take care to define your loop signals properly otherwise you get undesired effects regardless of the numeric problems below.

I don't know a standard way. With simulators, I am not familiar with the internals of PSpice but I did work on electronice device simulators, it is usual to solve a set of equations in a form that properly converge, i.e. after some initial values the values evolve in the direction of the solution like

x_n+1 = f(x_n)

so that for large enough n the values x_n+1 and x_n are about the same.

In this process it can happen, especially in the first steps, that non- physical intermediate values occur (e.g. values for carrier densities less than zero). This behaviour is AFAIK handled ad hoc, for the given quantity it is clipped to a physical useful value, i.e. meaning that every case is inspected and handled individually.

Rob

Why not just do a reality check of the two inputs and hold the output to a safe value until the loop settles?

Presumably your loops will include buffer registers, all of which will be (notionally) updated simultaneously. The rate of this update would match the sample rate of the system, and corresponds to the delay term Z^-1 in classical sampled circuit analysis. So the initial condition starts with "useful" (you will have to pick these) values in each register. Nothing happens until all the inputs have valid values. Then start up. The processing cycle being

for(ever) { for(each_block) compute_temporary_outputs for(each_register) update_value wait_for_sampling_interval }

u
s
t

=A0

You are already allowing the user to define the topology. Is there any reason not to also allow the user to define the initial outputs?

[...]

I was just experimenting with exactly this. The problem is, the loop can't really settle without some arbitrary choice being made. For example, in the loop that I described, the first "block" performs a division. If that block sees that input_b is zero, what "safe" value should it choose for its output? If it chooses zero, then the next block in the chain might have exactly the same problem, if it happens to also be performing a division. So the loop would never settle. Or worse, there could be a non-obvious chain that could lead to an unstable loop. Suppose a division block always chooses 1 as its output until things are settled. If two divide blocks' outputs go into a subtraction block, then the zero rears its ugly head again, and some division block further down the stream will have a problem.

This whole problem arises because the system itself, except for the inputs and outputs, is user defined, or maybe "programmable" is a better word. I need some sort of algorithm in the software that checks his design, before it is downloaded to the embedded system itself, that can make the correct (safe) choices for initial conditions.

Thank you for the suggestion. I am continuing to tinker with it...

Pat

I see the problem. Since you are representing numbers as floats, nonsensical values quickly become problems. And since you're allowing arbitrary or in your words "user defined" functions, you don't know what will be defined.

This is *not* a classic or simple embedded application. Most embedded aps have very well defined process goals and use integer arithmetic. At least the ones I've developed. With integers, you could easily represent the divide by zero output as a max integer, set a flag indicating that you're running open loop, pass the output down the process and not get into problems.

I think you should look hard at the decision to use floats and/or allowing arbitrary functions.

Good point. I wanted to avoid this, because it's difficult. It's very easy for the user to shoot himself in the foot in a non-obvious way. But automating this might become very complex. Just forcing the user to specifiy the initial conditions is probably the right answer. However, I think that it's an interesting problem to solve and plan to revisit it eventually. I was hoping there was already some standard way of dealing with this, simply because there are lots of systems out there where this issue would come up.

Thanks.

Understood. Yes, I guess this is a pretty complex system. The design, on my part, is pretty easy. But what the user might want to do with it is nearly unlimited. I guess it's only simple relative to other "programmable" systems.

Well, allowing arbirtrary functions is really the heart and soul. I think that Dingo's post in this thread summed up the approach that I should take: force the user to choose the initial conditions. If he does a poor job, then he gets an unstable system.

Thanks for all the replies.

for the

With a system as all-powerful and generic as you envision it, users _will_ shoot themselves in the foot, period. The trick is teaching them to like it ;-)

Actual analog synthesizers were always exceptionally tricky to work with

--- what makes you think a simulation of them should be any easier?

There isn't, because there aren't. There really aren't that many Simulink work-alikes out there.

If you allow loops he's quite likely to have an unstable system disirregardless of the initial conditions.

Best regards, Spehro Pefhany

"it's the network..." "The Journey is the reward" speff@interlog.com Info for manufacturers: http://www.trexon.com Embedded software/hardware/analog Info for designers: http://www.speff.com

... snip ...

Regardless, if he picks an appropriate configuration, he gets an unstable system. Possibly you can reduce this probability by controlling the values delivered on overflows.

[mail]: Chuck F (cbfalconer at maineline dot net) [page]: Try the download section.

Op Thu, 11 Sep 2008 21:22:25 +0200 schreef Pat :

You could have default initial conditions for each block type, possibly allowing the user to change them.

But you could also force sane initial conditions by having an "undefined" value, represented by a NaN. The blocks could then withold outputting a finite, real value until it makes sense to do so, e.g.:

  • divide undefined by undefined yields undefined
  • divide something by undefined yields something
  • divide undefined by something yields zero
  • add undefined to undefined yields zero
  • add something to undefined (or vice versa) yields something
Gemaakt met Opera's revolutionaire e-mailprogramma: http://www.opera.com/mail/

Unfortunately initial conditions are only part of the problem. A fully general system as described by the OP can have the fully general spectrum of bad behaviour.

The problem with that approach is that cycles in the operation graph can keep their "undefined" state indefinitely.

Except that NaNs don't work that way. By definition any operation with at least one NaN operand yields a NaN result.

Any solution that doesn't attempt to turn the system into a single equation, can have bad behaviour.

Exactly. The first few cycles should point that out, and this can be easily monitored by the VM. This perpetuous undefined state could mean that the system is unstable to begin with. But the option to let the user set an initial value (a "loop breaker") allows it to run anyway.

Yes, in IEEE-754 that's true. But we were using NaN's to represent something else, remember?

Gemaakt met Opera's revolutionaire e-mailprogramma: http://www.opera.com/mail/

[...]

Hmm... no, I don't. Can't seem to find any reference to these NaNs being any other than standard ones.

In other words: if these things are to behave in their own, different way, I consider it a mistake to call them NaNs.

Op Sun, 14 Sep 2008 23:46:15 +0200 schreef Hans-Bernhard Bröker :

Your search was in vain: I didn't say that they were different.

Indeed. We _call_ them "undefined", but they are _represented_ by NaNs.

Gemaakt met Opera's revolutionaire e-mailprogramma: http://www.opera.com/mail/

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required