Signal Routing Algorithm
PhreaK
Posts: 966
I'm in the process of putting together a module to handle signal routing in systems with complex signal distribution networks (stacked switchers, format conversion etc). At this point I'm thinking Dijkstra's algorithm may be a good solution and will allow paths to be mapped if I define the graph with a discrete vertex for each switch level on the matrix switchers and join them via nodes representing the video processors.
I'm just curious if others have implemented something similar in the past and if so what approach did you take?
P.S. once this gets to a functional state it'll be open sourced (along with the rest of the system) and should be pretty portable.
edit:
Done
I'm just curious if others have implemented something similar in the past and if so what approach did you take?
P.S. once this gets to a functional state it'll be open sourced (along with the rest of the system) and should be pretty portable.
edit:
Done
0
Comments
@DHawthorne standard interfaces are the way. The concept is to connect it to Duet module's that implement the SwitchComponent or SourceSelectComponent so that this is purely handling abstracted routing across the system and device communication remains separated.
@jimmyw yes, Dijkstras is shortest path, but you can assign lengths to the edges to influence the routing.
There's some more information and a bit of a discussion on the question I posted on StackExchange
I'm not sure what the problem you are trying to solve is. Is the shortest path the goal or some other metric, like least format conversions, etc? Typically networks use the (minimum) spanning tree algorithm to find a loop free path in a graph.
Paul
From my comment on the P.SE question:
How are the switches wired together?
Paul
The module should be flexible enough to work across different layouts. Basically instantiate, then pass in a identifiers for what's plugged in where (from channel names if you wish). This will then allow the edge data to be extrapolated and the graph formed.
Then that's tricky. You could easily end up with a situation where only a very limited number of paths are possible at the same time, and I assume concurrency is required. If they are daisy chained, a certain input/output selection could mean that few other independent, simultaneous paths are possible. If stacking 8 8x8 switches, and needing to route input 1 on switch 1 to output 1 on switch 8 would mean you couldn't route many other independent signals. Your graph would need to be redrawn for every i/o switch as the number of vertices available will shrink every time a switch is made, making many other routes impossible.
Wired that way you could have 54 inputs and 54 outputs available, but that severely limits how many simultaneous paths you can have. If you know you only have 8 inputs and 54 outputs, then you can wire things so that all sources go into one switch and then each output goes to its own switch. This limits the number of sources but then you can have all 8 inputs running independently on any or all of the 54 outputs, with the same switch hardware.
Since an input can be routed to any output(s), but an output can only receive one input, I guess you could use a modified Dijkstra's algorithm on whatever graph you are left with after pulling out any used outputs, to find the shortest vertex-independent path in the graph. Seems like overkill though.
Paul
For coversion to different signal types by switching in a converter (Translator), just to get to the device input that's available, you'll want to have a flag that ignores the path, so I don't see it as something that's optional for your approach. The ability to distiguish between signal types to get the best native resolution would be great for your algothithm to handle. It might be as easy as maintaining another edge components that give you the best signal type as part of your selection criteria.
I like your idea!
ROO
This is actually my first post. Got on here to look for a solution to something else and I saw this post. I actually just created a module to do a similar task. It allows me to use up to four switchers with unlimited inputs/outputs, an unlimited number of receivers and an unlimited number of displays. I execute a simple function call Route(source,zone,'audio'). The 'audio' can be either 'audio','video' or 'both'. It will exceute the switching, turn on or off the Receiver and/or display and select the proper input on the receiver or display. It currently only allows you to cascade two switchers, but it allows for all other configurations of Receiver to Display or even Display to Receiver. All the parameters are set in Structures. There is a structure for each Source, Zone, Receiver, and Display as well as one for each Switcher. To get around the different resolutions or Audio modes, I just create a second source with different parameters. It may not be the best way to do it, but all I have to do is set the structures up with the IO path and it works.
I've moved the functionality into a reusable graph library which I've added to the NetLinx Common Libraries project. It's currently in its own branch but I'm merge it into the master once the API is a bit more stable.
To use it for signal routing simply define a node for each signal source and sink as well as for each input and output on any switchers. From there add an edge for each cable in your system and an edge connecting each input to each output in each switcher. eg:
For signal processors (scalers etc) define a node for the input and output and add a weighted edge joining them so that signal flow is biased towards keeping things in native formats.
If you've got multiple trunk lines connecting switchers simply vary the edge weight when they're in use to redirect to unused links. Also, if you are monitoring devices and a device fails simple set the edge weighting to and from it to GRAPH_MAX_DISTANCE. This allows you to have an auto healing signal network in high availability systems with redundant links.
After that is done just run graph_compute_paths() for a source node then use graph_get_shortest_path() with your destinations of interest to get the optimum path. By inspecting the nodes that form the path you can then make any switching changes.
I'm going to try and put together a little helper library that wraps this for use within signal routing. It should then give you some pretty simple features for graph creation like defineSource(), defineSink(), defineSwitcher(inputs, outputs) and a route(source, destination) which will give a list of switches that need to be made in SNAPI format.
Anyway, here it is in its current unoptimized state: https://github.com/KimBurgess/netlinx-common-libraries/blob/graph/graph.axi.
If you can make it better fork it and submit a pull request. Otherwise if you just want to use it go for. I've built it with handling signal distribution in mind by if you think of another use I'd love to hear about it.
Basically define your switching gear, define your sources and sinks (displays, recorders etc) then just call route(source, sink) and it will send any SNAPI commands to the switchers that need to do things. It's still pretty rough but you get the idea.
This will only create nodes and edges where needed which drastically reduces the graph complexity. With this even in a rather sizable network with multiple layers of stacking and rather complex routes you should expect sub 100ms graph traversal for the initial computation. As this is buffered sequential calls to route the same source to any sink take around 1ms. Basically this thing will now generate the control strings for your switching gear faster than they can be executed.
As always, improvements can always be made so if you can make it better please forking* do it.
*full geek pun intended.