Simulating simple electric circuits

  • Thread starter Bjoern Schliessmann
  • Start date
B

Bjoern Schliessmann

Hello all,

I'm trying to simulate simple electric logic (asynchronous)
circuits. By "simple" I mean that I only want to know if I
have "current" or "no current" (it's quite digital) and the only
elements need to be (with some level of abstraction to my specific
problem)

- sources (here begin currents)
- ground (here end currents)
- joints
- switches (which are able to let current pass or not, depending on
outside influence)
- loads (which can signal change in current flow to the outside --
just like a light bulb)

Is there any library for this? I couldn't find one.

I tried to implement this using objects that are two-way linked;
every object has "ports". For every port, there is

- an input function (that is called by the neighbour if "current"
comes in)
- a reference to the neighbour's input function, to be able to let
current flow the other way

There is a master "current controller" object which tells
the "source" object to start a "current" by calling its neighbour.
The calls traverse the network until they reach a "ground" object.
Specifically, the source passes a "telegram" instance with these
calls, and everyone it passes through "registers" himself with it
(telegrams are duplicated at joints). Then, the ground object calls
back to the controller with all received telegrams. Like this I'm
already able to get all possible ways through the network.

But that's where my ideas go out. Let's assume there is a load in
the middle of such a current, e. g. a light bulb. So if the current
flows through it it gets notice of this because there is a telegram
passing through it. But what if a contact before it now "cuts" the
current, how could I notify all objects behind the cut? I tried
several ways the past few days, but all lead to confusing (and
non-working) code. (I'm sorry I can't provide any working code yet)
Often it boils down to the need to check all possible ways in the
entire network with every change. This shouldn't, in perfomance
terms, be a big problem for me here, but it feels very dirty, and I
smell inconsistencies.

Another way I thought of is

- to let load objects have a timer that resets their state to "no
flow" after ~ 200 ms
- "pulse" the network every ~ 100 ms from all sources to ground
- and reset all load timers on the way.

This feels even more dirty.

There are several professional-grade simulation tools that track
many other parameters, how do they work in general, is there a
different strategy? I wonder if I'm making it too complicated or if
I'm seeing problems where there really aren't any. I also looked at
NetworkX, but I can't see how it might be of use yet. I appreciate
all suggestions.

Thanks for you consideration.

Regards,


Björn

P.S.: This is no homework, it's pure hobby ;)
 
A

Arnaud Delobelle

Hello all,

I'm trying to simulate simple electric logic (asynchronous)
circuits. By "simple" I mean that I only want to know if I
have "current" or "no current" (it's quite digital) and the only
elements need to be (with some level of abstraction to my specific
problem)

- sources (here begin currents)
- ground (here end currents)
- joints
- switches (which are able to let current pass or not, depending on
outside influence)
- loads (which can signal change in current flow to the outside --
just like a light bulb)

Is there any library for this? I couldn't find one.

I tried to implement this using objects that are two-way linked;
every object has "ports". For every port, there is

- an input function (that is called by the neighbour if "current"
comes in)
- a reference to the neighbour's input function, to be able to let
current flow the other way

There is a master "current controller" object which tells
the "source" object to start a "current" by calling its neighbour.
The calls traverse the network until they reach a "ground" object.
Specifically, the source passes a "telegram" instance with these
calls, and everyone it passes through "registers" himself with it
(telegrams are duplicated at joints). Then, the ground object calls
back to the controller with all received telegrams. Like this I'm
already able to get all possible ways through the network.

Then you can get all 'potential' paths that depend on one or more
switches being on. Each path could know what switches it depends on
and be 'active' if and only if all those switches are on. And each
switch would know what paths depend on it. Similarly each lightbulb
would know what paths it depends on and be 'on' if at least one path
is active; and each path would know which lightbulbs it powers
But that's where my ideas go out. Let's assume there is a load in
the middle of such a current, e. g. a light bulb. So if the current
flows through it it gets notice of this because there is a telegram
passing through it. But what if a contact before it now "cuts" the
current, how could I notify all objects behind the cut? I tried
several ways the past few days, but all lead to confusing (and
non-working) code. (I'm sorry I can't provide any working code yet)
Often it boils down to the need to check all possible ways in the
entire network with every change. This shouldn't, in perfomance
terms, be a big problem for me here, but it feels very dirty, and I
smell inconsistencies.

When you turn a switch off, it would send a message to the paths that
depend on it (maybe via the controller?) so that they would be
deactivated. In turn the lightbulbs on these paths would be informed
that they are no longer active.

When you turn a switch on, it would send a message to the paths that
depend on it so that those who do not have another off switch would be
activated. In turn the lightbulbs on these paths would be informed
that they have a new power source.

It seems to me that it would work well with the way you started it
out, but I may have misunderstood some aspects or overlooked some
problems ;)
 
B

Bjoern Schliessmann

Arnaud said:
On May 7, 7:05 pm, Bjoern Schliessmann <usenet-

Then you can get all 'potential' paths that depend on one or more
switches being on. Each path could know what switches it depends
on and be 'active' if and only if all those switches are on. And
each switch would know what paths depend on it. Similarly each
lightbulb would know what paths it depends on and be 'on' if at
least one path is active; and each path would know which
lightbulbs it powers

In principle, I thought so too, but I didn't like the fact that this
involves all possible circuits be determined only once. But it
seems like there is no reasonable, different way.
When you turn a switch off, it would send a message to the paths
that depend on it (maybe via the controller?) so that they would
be deactivated. In turn the lightbulbs on these paths would be
informed that they are no longer active.

When you turn a switch on, it would send a message to the paths
that depend on it so that those who do not have another off switch
would be activated. In turn the lightbulbs on these paths would
be informed that they have a new power source.

Yep. Looks like I have to do extended "bookkeeping" for this. I was
looking for a more dynamic, general way.
It seems to me that it would work well with the way you started it
out, but I may have misunderstood some aspects or overlooked some
problems ;)

Thanks for your input. The biggest problem I got until now are the
crummy interfaces for interconnection which quickly get inconcise.
I've had a look at the NetworkX tutorial and it seems like this
could simplify the code a bit.

Regards,


Björn
 
T

Terry Reedy

in message Hello all,

| I'm trying to simulate simple electric logic (asynchronous)circuits.
[snip]

Some network simulators use connection objects in addition to node objects,
with connections joined to nodes but not the same type to each other. But
I do not see this as applying here.

Another 'trick' is to make all connections one-way, so a two-way connection
is a pair of opposite one-way connections. This might make it easier to
keep track of what is turning on (or off) what.

tjr
 
D

Dave Baum

Hello all,

I'm trying to simulate simple electric logic (asynchronous)
circuits. By "simple" I mean that I only want to know if I
have "current" or "no current" (it's quite digital) and the only
elements need to be (with some level of abstraction to my specific
problem)

- sources (here begin currents)
- ground (here end currents)
- joints
- switches (which are able to let current pass or not, depending on
outside influence)
- loads (which can signal change in current flow to the outside --
just like a light bulb)

Are you trying to do logic simulation (digital) or analog circuit
simulation? The only reason I ask is that the simulation techniques are
very different, and you used both "logic" and "current" in your
description, so I'm not quite sure which direction you are heading.


For analog:

If you are ignoring time related effects (no inductance or capacitance),
then the system is solvable as a set of linear equations. Basically
your circuit consists of a set of nodes and edges. Wires are edges,
joints are nodes. An open switch is nothing, a closed switch is an
edge. A load is an edge. You'll have to assign resistances to the
edges (anything non-zero will do) in order for the equations to make
sense. Then you can use Kirchoff's laws to analyze the circuit and
construct the equations to solve. A good linear algebra library (numpy)
will help in solving the equations.

Opening or closing a switch would result in a new set of equations, and
thus a new solution. You might be able to get clever and model open
switches as edges with infinite resistance, which would allow you to
skip the Kirchoff stuff each time a switch is flipped. You'd only have
to change coefficients and solve the system of equations. However, the
system of equations would be singular, so you'd have to do something
like an SVD rather than an inverse.

I don't want to go into too much more detail about this one because I
have a hunch you are really looking at digital, but if you're interested
in the analog approach let me know and I'll fill in more of the details.


For digital:

Event based simulation is typical here. These simulations generally are
concerned with voltage, not current. A circuit consists of signals and
devices. At any given time, each signal has a certain state (high/low,
on/off, 9 level logic, whatever). Devices are connected to one another
by signals. You'll also need events (a signal, a time, and a new
state), and an event queue (events sorted by time). This is easier if
each signal is driven by at most one device:

1) pop the next event off the queue
2) if the event's signal's state is the same as the new state, go to 1
3) set the event's signal's state to the new state
4) for each device that is attached to the signal, run the device's
code, which should look at all of its inputs, and post new events to the
queue for any outputs (do this even if the computed output is the same
as the current output). These events are usually posted for some time
in the future (1 simulation 'tick' is fine).
5) go to 1

This approach is pretty simple to do in Python. I wrote a sample
digital simulator a while back and the core of the simulator was around
50 lines of code. Rounded out with some basic logic gates and helper
functions to probe the simulation, it was around 150 lines. It was only
2 level logic and signals could only be driven by a single device.

The devices that you want to model (switches, loads, etc) don't have
explicit inputs and outputs, and you'll need to deal with a signal being
driven from multiple sources, so it will get a bit more complicated.
You will probably also need 9 level logic (or something equivalent) to
deal with the fact that ground beats a source through a load when
determining a node's state.

The basic idea is that each signal has multiple drivers, each of which
has an internal state. When a device wants to set an output, it only
changes its driver's state. The signal then has code that looks at the
state of all drivers and combines them in some way (this is called a
resolution function). That combined state is what devices see when they
read the signal.

It isn't *that* complicated to implement, but if you can turn your
problem into one with 2 level logic and no multiple drivers, then it
will be easier to write and debug.

Dave
 
S

Stef Mientki

hi Bjoern,

Bjoern said:
Hello all,

I'm trying to simulate simple electric logic (asynchronous)
circuits. By "simple" I mean that I only want to know if I
have "current" or "no current" (it's quite digital) and the only
elements need to be (with some level of abstraction to my specific
problem)

- sources (here begin currents)
- ground (here end currents)
that doesn't bring you anywhere ;-)
Current doesn't start or end at some location,
current flows through a closed circuit.

And that's the first law you need: Kirchoff's current law:
the total current in every node is ZERO !!

The second formula you need: Kirchoff's voltage law,
the sum of all voltages following any closed loop is ZERO.

That's all you need,
it gives you a set of linear equations,
enough to let them solve by SciPy / NumPy.

And let's forget about capacitors, inductors and semi-conductors for this moment !

Here is a simulation package, although designed for MatLab,
it might give you a good idea of what your need.
http://www.swarthmore.edu/NatSci/echeeve1/Ref/mna/MNA6.html


There are few simulation related packages,
but not directly suited for electronics
http://www.mcs.vuw.ac.nz/cgi-bin/wiki/SimPy
http://www.linuxjournal.com/article/7542
http://pyastra.sourceforge.net/
http://www.nelsim.com/scriptsim/python_man.html

As an little test I wrote a PIC simulator (only core) in Python,
it's very rough code (generated in a few evenings),
if you're interested I could look it up.

cheers,
Stef Mientki
 
B

Bjoern Schliessmann

Stef said:
Bjoern Schliessmann wrote:
that doesn't bring you anywhere ;-)

It does :)
Current doesn't start or end at some location,
current flows through a closed circuit.

The part I omit is the voltage source. All currents I need in my
system flow from plus to ground.
And let's forget about capacitors, inductors and semi-conductors
for this moment !

Yep, because I largely don't have any here, only in few special
cases (where I also can use some kind of "current priority").
Here is a simulation package, although designed for MatLab,
it might give you a good idea of what your need.
http://www.swarthmore.edu/NatSci/echeeve1/Ref/mna/MNA6.html

Wow ... Overkill :)
There are few simulation related packages,
but not directly suited for electronics
http://www.mcs.vuw.ac.nz/cgi-bin/wiki/SimPy

I once looked at this, but couldn't find out how to use it with my
problem. :\

Those are all a bit daunting ...
As an little test I wrote a PIC simulator (only core) in Python,
it's very rough code (generated in a few evenings),
if you're interested I could look it up.

Thank you for the offer. I'm presently having problems understanding
even the examples, so I'll call in if I get so far.

Regards,


Björn
 
B

Bjoern Schliessmann

Dave said:
Are you trying to do logic simulation (digital) or analog circuit
simulation?

Mh, a mix of both :) I want to simulate (in principle simple)
magnetic relay circuits. The only "evil tricks" that are used are

- shortcuts (e. g. a relay coil is bypassed and thus the relay gets
no voltage and it relaxes)
- low currents (so a relay has current but doesn't switch)
I don't want to go into too much more detail about this one
because I have a hunch you are really looking at digital, but if
you're interested in the analog approach let me know and I'll fill
in more of the details.

Good hunch :) But thanks for the explanations. The fully analog
network approach is definitely overkill here.
For digital:

Event based simulation is typical here. These simulations
generally are concerned with voltage, not current. A circuit
consists of signals and devices. At any given time, each signal
has a certain state (high/low, on/off, 9 level logic, whatever).
Devices are connected to one another by signals. You'll also need
events (a signal, a time, and a new state), and an event queue
(events sorted by time). This is easier if each signal is driven
by at most one device:

1) pop the next event off the queue
2) if the event's signal's state is the same as the new state, go
to 1
3) set the event's signal's state to the new state
4) for each device that is attached to the signal, run the
device's code, which should look at all of its inputs, and post
new events to the queue for any outputs (do this even if the
computed output is the same as the current output). These events
are usually posted for some time in the future (1
simulation 'tick' is fine).
5) go to 1

This approach is pretty simple to do in Python. I wrote a sample
digital simulator a while back and the core of the simulator was
around 50 lines of code. Rounded out with some basic logic gates
and helper functions to probe the simulation, it was around 150
lines. It was only 2 level logic and signals could only be driven
by a single device.

The devices that you want to model (switches, loads, etc) don't
have explicit inputs and outputs, and you'll need to deal with a
signal being driven from multiple sources, so it will get a bit
more complicated. You will probably also need 9 level logic (or
something equivalent) to deal with the fact that ground beats a
source through a load when determining a node's state.

The basic idea is that each signal has multiple drivers, each of
which has an internal state. When a device wants to set an
output, it only changes its driver's state. The signal then has
code that looks at the state of all drivers and combines them in
some way (this is called a resolution function). That combined
state is what devices see when they read the signal.

It isn't *that* complicated to implement, but if you can turn your
problem into one with 2 level logic and no multiple drivers, then
it will be easier to write and debug.

Sounds more familiar than the analog approach. Maybe I misunderstood
something ... but I can't transfer my problem to this way of
thinking yet. My biggest problem is the fact that relays aren't
really interested in voltage, but current.

Also, I find it difficult to transfer this circuit logic to boolean
logic I can contruct logic gates from. Sometimes, electric circuits
are used in different directions.

This is how far I've come with my first approach yet:

I set up the mentioned "controller" which, at the beginning, tries
out all possible ways through the network and saves them. So, for
every possible circuit it knows which switches must be closed and
which relays will work if it's "on". In theory, it should now be
possible to try out every path, tell the relays if they have
voltage/current, and let the relays report back in to the
controller if their status changes so it can again test the
circuits that may have changed. I haven't tried out the last step,
but I will in the next days. Is there any logic error in my
strategy?

Regards,


Björn
 
B

Bjoern Schliessmann

Arnaud said:
When you turn a switch off, it would send a message to the paths
that depend on it (maybe via the controller?) so that they would
be
deactivated. In turn the lightbulbs on these paths would be
informed that they are no longer active.

When you turn a switch on, it would send a message to the paths
that depend on it so that those who do not have another off switch
would be
activated. In turn the lightbulbs on these paths would be
informed that they have a new power source.

Wow, as I read your reply again, this is exactly the approach I
thought of yesterday. :) As mentioned in an adjacent posting, I'll
try it out.

Thanks to all for comments. This list is great. :)

Regards,


Björn
 
D

Dave Baum

Sounds more familiar than the analog approach. Maybe I misunderstood
something ... but I can't transfer my problem to this way of
thinking yet. My biggest problem is the fact that relays aren't
really interested in voltage, but current.

Also, I find it difficult to transfer this circuit logic to boolean
logic I can contruct logic gates from. Sometimes, electric circuits
are used in different directions.

Yep, the traditional digital simulation techniques don't apply very well
to things like switches and relays. Going with a different approach is
probably cleaner.
I set up the mentioned "controller" which, at the beginning, tries
out all possible ways through the network and saves them. So, for
every possible circuit it knows which switches must be closed and
which relays will work if it's "on". In theory, it should now be
possible to try out every path, tell the relays if they have
voltage/current, and let the relays report back in to the
controller if their status changes so it can again test the
circuits that may have changed. I haven't tried out the last step,
but I will in the next days. Is there any logic error in my
strategy?

Sounds reasonable. Depending on the size of your network, I might not
worry too much about precomputing and saving information. If your
circuit has loops in it (where the output of a later relay circles back
to an earlier relay's coil), then it is possible for the circuit to
oscillate, so you might have to be careful about this. For example, if
your basic simulation flow was:

1) set initial conditions (switches, etc)
2) let power flow through the system
3) determine which relays will be thrown
4) if any relays have changed state, go to 2

Then an oscillating circuit would never quit. You might want to put a
limit on the number of iterations through the loop, or logic that
explicitly checks for oscillation. Or you could analyze the circuit
ahead of time to see whether it has oscillation or not.

Dave
 
B

Bjoern Schliessmann

Dave Baum wrote:
Sounds reasonable. Depending on the size of your network, I might
not worry too much about precomputing and saving information.

Thanks. Yes, I'm actually testing it presently without any
optimizations and it runs very well.
If your circuit has loops in it (where the output of a later relay
circles back to an earlier relay's coil), then it is possible for
the circuit to oscillate, so you might have to be careful about
this.

That's no substancial problem, with real relay circuits this happens
sometimes too :) (even in the systems I'm modelling)

After all, I'm quite pleased now with how well the last approach I
mentioned works. I've been able to model a medium complex switching
sequence today, and it worked flawlessly.

(The only problem I have now arises when I make relays react
delayed, using Twisted's reactor.callLater. Sometimes, a relay gets
current and loses it shortly after, but the event loop in rare
cases executes the status change functions the other way round ("no
current", then "current"). I've been trying to fix that by
detection if a timer already runs. Anyhow, the inconsistencies only
vanish if I let the relays react delayless again. I'm going to have
to look into this further ...)


Regards,


Björn

P.S.: If anyone happens to be interested in details, just ask, I'll
post some code.
 
A

Arnaud Delobelle

On May 11, 10:02 pm, Bjoern Schliessmann <usenet-
(e-mail address removed)> wrote:
[...]
P.S.: If anyone happens to be interested in details, just ask, I'll
post some code.

I'm interested! I was tempted to have a go at it after your initial
post, it sounded like a nice little project :)
 
B

Bjoern Schliessmann

Arnaud said:
I'm interested! I was tempted to have a go at it after your
initial post, it sounded like a nice little project :)

Please stand by a day. I'm momentarily facing problems with currents
that never end (going in a circle). And my code doesn't look that
beatiful and/or clean to me, as is using this framework. But judge
yourself (soonest tomorrow). I'm already looking forward to
comments and suggestions. :)

Regards,


Björn
 
B

Bjoern Schliessmann

Arnaud said:
I'm interested! I was tempted to have a go at it after your
initial post, it sounded like a nice little project :)

Here you go, see below (quite long). It works from Python 2.5
and above and should be straightly executable from command line.

(It'll work with lower Python versions if you backtranslate the
few "A if (condition) else B" parts.)

We have:
- class CurrentController which does the main work
- classes Source and Ground for convenience when creating circuits
- class Relay for the realisation of logic

Please have a look at the example at the end. It's taken from my
actual project. A relay "ZT" is brought up if an outside key is
pressed. This forces the normally-"up" latching relay "ZTS" down.
This in turn causes relay "FTS" to go "up" (which causes many
other complicated stuff).

I'm open for questions and/or suggestions. :) The names used and
docstrings may sound a bit strange since I hastily translated the
source from german (we have some very special terms regarding relay
technology).

I suspect that this is a dead end though, because in more complex
designs the creation of circuits becomes cumbersome. Also, for the
system I want to model, the circuits are OOH very complex and OTOH
I don't have access to all circuit diagrams. :( So I think I'll try
next to transfer my problem to digital two-level logic.

I'll go with Dave Baum's suggestion with the event queue and post
again here soon with report of my achievements ...

Regards,


Björn

---snip---
#!/usr/bin/env python

class CurrentController(object):

def __init__(self):
self.currentSources = {}
# Contents: {ID1: source1, ID2: source2, ...}
self.circuits = {}
# Contents: {ID1: [all circuits starting at source 1],
ID2: [...], ...}

def newID(self):
ID = 0
while ID in self.currentSources:
ID += 1
return ID

def newSource(self, func = None):
id = self.newID()
s = Source(id, func)
self.currentSources[id] = s
return s

def newGround(self):
e = Ground()
return e

def newRelay(self, name, **argv):
r = Relay(name, **argv)
return r

def changed(self, relay):
"""
Relay relay changed. Re-try all circuits containing it.
"""
print "CurrentController: changed:", relay.name, "up" if relay.up else "down"
for ID, circuits in self.circuits.items():
for circuit in circuits:
if circuit.contains(relay):
circuit.test()

def showCircuits(self, activeOnly = False):
"""
Show all circuits.

If activeOnly is True, show only active ones.
"""
print "| Circuits: "
for ID, circuits in self.circuits.items():
print "| ID: %i" % ID
for circuit in circuits:
if (not activeOnly) or circuit.active:
print circuit


def start(self):
"""
All circuits are defined -- try them out and start
monitoring changes.
"""
for ID, source in self.currentSources.items():
source.start()

for ID, circuits in self.circuits.items():
for circuit in circuits:
circuit.test()



def toGround(self, telegram):
"""
Save telegram as valid circuit and monitor it.

Called from the outside if a telegram reaches "ground"
(i. e., circuit closed).
"""
try:
self.circuits[telegram.ID].append(telegram)
except KeyError:
self.circuits[telegram.ID] = [telegram]

class CurrentTelegram(object):
"""
Class for recording and managing a circuit.
"""
usedIDs = []

def __init__(self, id):
self.relays = []
# Contents: [(group name, relay object, coil function), ...]
self.switches = []
# Format: [(group name, relay object, switch function), ...]

self.ID = id # ID of the source of this telegram
self.circuitID = self.newID() # unique telegram ID

# default priority is 1. Should always be > 0.
# It's used for weighing of multiple currents, see Relay class.
self.prio = 1
self.active = False

def newID(self):
ID = 0
while ID in self.usedIDs:
ID += 1
self.usedIDs.append(ID)
return ID

def __str__(self):
relays = [""] # for an extra newline at the beginning of the string to return
for group, r, f in self.relays:
type = repr(f)
temp = "||| Group %s, Relay %s %s" % (group, r.name, type)
relays.append(temp)
relays = "\n".join(relays)

switches = [""]
for group, r, f in self.switches:
type = repr(f)
temp = "||| Group %s, Relay %s %s" % (group, r.name, type)
switches.append(temp)
switches = "\n".join(switches)

return """|| CurrentTelegram
|| Source %i
|| Relays: %s
|| Switches: %s
|| %sactive
||""" % (self.ID, relays, switches, "" if self.active else "not ")

def __repr__(self):
return self.__str__()

def copy(self):
"""
Generate and return a copy of this telegram
(for current "forks")
"""
other = CurrentTelegram(self.ID)
other.relays = self.relays[:]
other.switches = self.switches[:]
other.prio = self.prio
other.active = self.active
# self.active should at this point normally be always False
# circuits aren't added after CurrentController.start is
# called
return other

def addSwitch(self, byWho, relay, f):
"""
Add a switch to the circuit. Parameters:
- byWho: Name of caller (for information only)
- relay: Relay object
- f: A callable. If it returns True or equivalent,
switch is "closed", else "open".
"""
self.switches.append((byWho, relay, f))

def addRelay(self, byWho, relay, f):
"""
Add a relay to the circuit. Parameters:
- byWho: Name of caller (for information only)
- relay: Relay object
- f: A callable ("coil function"). It's called
as f(True) if the circuit gets active,
and f(False) if it becomes inactive.
"""
self.relays.append((byWho, relay, f))

def contains(self, relay):
return self.containsRelay(relay) or self.containsSwitch(relay)

def containsRelay(self, r):
for _, relay, __ in self.relays:
if relay is r:
return True
else:
return False

def containsSwitch(self, r):
for _, relay, __ in self.switches:
if relay is r:
return True
else:
return False

def mayBecomeActive(self):
"""
Determine if circuit is "closed" (i. e. all switches
are closed so current can flow).
"""
for name, relay, f in self.switches:
if not f():
break
else:
return True
return False

def becomeActive(self):
"""
Make circuit active: Give "current" to all relays
in this circuit.
"""
if self.active: return
self.active = True

for name, relay, f in self.relays:
# Also give circuitID for relay to know who activated it
f(True, self.circuitID)

def stop(self):
"""
Make circuit inactive: Relay falls
"""
if not self.active: return
self.active = False

for name, relay, f in self.relays:
# Also give circuitID for relay to know who deactivated it
f(False, self.circuitID)

def test(self):
if self.mayBecomeActive():
self.becomeActive()
else:
self.stop()

# TODO: Eliminate circle currents


currentController = CurrentController()

class Source(object):
def __init__(self, ID, neighbour = None):
self.connections = []
self.ID = ID
if neighbour: self.verbindungen.append(neighbour)

def start(self):
"""
Create CurrentTelegrams and send them to
all connected.
"""
for c in self.connections:
t = CurrentTelegram(self.ID)
c(t)

class Ground(object):
c = currentController
def input(self, t):
self.c.toGround(t)

class Relay(object):
c = currentController
"""
Continuous current relay/latching relay

TODO: Delay!
"""
def __init__(self, name, latching = False, initiallyUp = False, minStrength = 1):
self.up = False if not initiallyUp else True
self.name = name
self.latching = True if latching else False

# In here, pairs "Circuit-ID: strength" of currents through
# raising coil are saved
self.currents = {}

# This helps decide when Relay goes to "up":
# If the sum of all "flowing" strengths in
# self.currents is >= minStrength.
#
# Example: minStrength = 2.
# => The relay will go to "up" if at least
# - one current of strength "2"
# - two currents of strength "1" each
# - ...
# are active.

self.minStrength = minStrength

def strengthBigEnough(self):
"""
Test the magnitude of the sum of all currents through
the "raise" coil. If it's big enough, return True,
else False.
"""
total = 0
for _,strength in self.currents.items():
total += strength

return True if total >= self.minStrength else False

def normalSw(self):
"""
Normal switch -- is closed if relay is "up",
else open.
"""
return True if self.up else False

def reverseSw(self):
"""
Reverse switch -- opens if relay is "up",
else it's closed.
"""
return True if not self.up else False

def normalCoil(self, status, circuitID, strength = 1):
"""
Send a "current" through the normal coil.

Relay goes "up" if status is True or equivalent.

Else, if no currents remain and relay is no
latching relay, it goes to "down".
"""
if status:
assert circuitID not in self.currents
self.currents[circuitID] = strength
if self.strengthBigEnough():
self.goUp()
else:
del self.currents[circuitID]

if not self.strengthBigEnough():
if not self.latching:
self.goDown()

def forceDownCoil(self, status, circuitID):
"""
Relay goes down, no matter what.
"""
if status:
self.goDown()
# CurrentController will be notified of change here
# and will retry all circuits through normal coil,
# so it's okay to ignore self.currents here

def goUp(self):
if not self.up:
self.up = True
self.c.changed(self)

def goDown(self):
if self.up:
self.up = False
self.c.changed(self)

def __str__(self):
return "Relay %s: %s%s (Currents: %r)" % (self.name,
"up" if self.up else "down",
" (latching relay)" if self.latching else "",
self.currents)
def __repr__(self):
return self.__str__()

# following not in main method for usability of "python -i"

# create some relays
ZT = currentController.newRelay("ZT")
FTS = currentController.newRelay("FTS", latching = True)
ZTS = currentController.newRelay("ZTS", latching = True, initiallyUp = True)

# create one source and one ground
s = currentController.newSource()
g = currentController.newGround()
name = "tester"

def circuit1(t):
t.addSwitch(name, ZT, ZT.normalSw)

u = t.copy() # fork!
u.addRelay(name, ZTS, ZTS.forceDownCoil)
g.input(u)

t.addSwitch(name, ZTS, ZTS.reverseSw)
t.addRelay(name, FTS, FTS.normalCoil)
g.input(t)

s.connections.append(circuit1)

# example circuit:
#
# V (+)
# |____________________________
# | |
# _|_ ZT sw (closes when up) |_ ZTS sw (opens when up)
# | |
# | ^ |
# O | ZTS ("force down" coil) O FTS (normal coil)
# | ("up" at beginning) |
# | |
# --- GND --- GND
#

def main():
currentController.start()
print "Putting ZT up with my finger ..."
ZT.goUp()

currentController.showCircuits()

if __name__ == "__main__":
main()
---snap---
 
B

Bjoern Schliessmann

Bjoern said:
class Source(object):

Little bug: The __init__ method of class Source should look like
this.

def __init__(self, ID, neighbour = None):
self.connections = []
self.ID = ID
if neighbour: self.connections.append(neighbour)

Regards,


Björn
 
B

Bjoern Schliessmann

Bjoern said:
I suspect that this is a dead end though, because in more complex
designs the creation of circuits becomes cumbersome. Also, for the
system I want to model, the circuits are OOH very complex and OTOH
I don't have access to all circuit diagrams. :( So I think I'll
try next to transfer my problem to digital two-level logic.

Erm, no. Doesn't work. I'll still stick with the circuit
approach ...

Regards,


Björn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top