1

I have a QMap<int, MyData> where the key is the address of Modbus register, and MyData is my own struct that contains some information not important for this question.

The keys set might be quite large (say 2000 values) with some of them close each other. For example:

1, 2, 3, 4, 7, 23, 24, 25, 40, 41, 43, ...

My goal is to end up with a QList<QPair<int,int>> where the items of the QPair class are the lower and upper bounds of each Modbus request I will send. This list should be optimized to join together consequential values or values "very close" each other. This is to reduce the number of Modbus requests with a trade-off with the amount of data requested.

In the example above I would like:

[1, 7], [23, 25], [40, 43]  

I'm going to set a couple of constraints to give a weight for each request. Requesting data from address 1 to 7 is worth than 1 to 4 and then only 7, but it isn't if the 7 was 16... Another constraint is the maximum length of a single request: even if there are a lot of consequential addresses they must be splitted in segments of length N.

I'm asking some guidelines how to approach such a problem.

What I thought until now. Create a second array with the difference between element x and x-1:

1, 2, 3, 4, 7, 23, 24, 25, 40, 41, 43, ...
   1, 1, 1, 3, 16,  1,  1, 15,  1, 2, ...

Then scan this array and find any number below the "weight threshold" (let's say is 4) and create the first QPair list including those addresses:

[1, 7], [23, 25], [40, 43]

Finally, check the length of each couples and if greater than the maximum allowable split it.

Do you think is a reasonable approach? Is there some well-known algorithm that might fit here? Does a QMap is a good choice? I used this because I'm going to emit a signal when I receive each value from the Modbus like this:

void dataReceived(int address, quint16 value);

hence would be very easy to retrieve the related MyData.

Mark
  • 4,338
  • 7
  • 58
  • 120
  • 1
    For real life applications your approach seems fine. In theory you could define a cost function for every command you send and solve an optimization problem to minimize the total cost. The cost function could look like this: Cost(cmd)=const1+const2*Nreg where Nreg - the number of requested registers. But I doubt that the effort will be worth it. – algrid Sep 11 '18 at 21:48
  • I see, it's anyway another point of view to get the point. My "weight threshold" is close to your "cost", but in any case the difficulty is to estimate them correctly. Packets' lengths and delay in answers are the main contribution to that cost I guess. – Mark Sep 12 '18 at 06:03
  • You forgot some words in the question. What function specifically are you using? – Kuba hasn't forgotten Monica Sep 13 '18 at 18:38
  • Mainly F3: read holding register – Mark Sep 13 '18 at 19:15

1 Answers1

3

The solution you thought is great. It solves the problem in O(n) complexity. In terms of complexity can not be better than this. Since to build the list is needed to traverse all the elements. But... you can do it a little faster (assuming that the array is sorted)

To build the list QList<QPair<int,int>> you are doing three iterations of size n.:

1 - Build the array with the differences.

2 - Create the list traversing the array built in the previous step

3 - Check the length of each couples and if greater than the maximum allowable split it.

You can do it in only one iteration (one step); Keeping track of variables start, end of the pair and the size. When you find a value that has a difference greater than the "weight threshold" from the previos value or the size is greater than the "maximun allowable" then -> Add the pair to the list and reset the variables start, end and size with the next value.

Anyway since the list is only 2000 values max it is not a big diference.

About your other question. Yes QMap is an excellent choice since provide O(1) time complexity to retrive your data.

jpincz
  • 146
  • 8
  • Perhaps my question is a bit misleading but I'm more interested to optimize the requests than the algorithm itself. I mean, the procedure may take a lot of time because it's executed once at startup. I'm wondering if my assumptions are correct to minimize the time needed to read all the values from Modbus. – Mark Sep 12 '18 at 05:59