Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build circuit structures flexibly #153

Open
HongRi0716 opened this issue Apr 28, 2022 · 15 comments
Open

Build circuit structures flexibly #153

HongRi0716 opened this issue Apr 28, 2022 · 15 comments

Comments

@HongRi0716
Copy link

HongRi0716 commented Apr 28, 2022

Description

Different parallel branches can be set, and the battery on each branch can be arbitrarily bypassed .

Motivation

Simulate the behaviour of systems which combine aged/non-aged cells;
According to states of cells, reconfigure the circuit structures to achive cell balancing.

Possible Implementation

The circuit can be built by a similar association matrix or loop matrix.

Additional context

No response

@TomTranter
Copy link
Collaborator

Hi @HongRi0716 is this something you have started working on?

@HongRi0716
Copy link
Author

@TomTranter No. We are just going to use reinforcement learning for reconfigurable batteries to achieve cell balancing. We are trying to establish a simulation environment for reconfigurable batteries, possibly through Python or MATLAB.

@TomTranter
Copy link
Collaborator

@HongRi0716 sounds interesting, are you academia or industry? Re-configuring the grid would be reasonably straightforward I think

@bessman
Copy link

bessman commented May 6, 2022

I'm also interested in this feature. If you think it's a good fit for liionpack I could take a look at implementing it. Could you @TomTranter give me a hint for where to start digging?

@TomTranter
Copy link
Collaborator

In the first instance it seems like the most straight-forward thing to do would be to increase the connection resistance along a string in order to bypass the branch. I have never tested the code doing this so may cause numerical issues but it should be ok. Then if that doesn't work the next easiest solution would be to run a simulation and save the results then generate a new netlist and instantiate the cell models from the previous results. Saving and restarting is something that should be introduced anyway. Question becomes what happens to the cells that have been disconnected. Are they still included in the simulation for modelling thermal and equilibriation. Ideally I guess we'd just define some extra electronic components like switches etc but I don't really want to go too far down that route as I think we'd be reinventing the wheel a lot of the time when maybe in future we can leverage spice or something to do all the circuit solving

@bessman
Copy link

bessman commented May 10, 2022

increase the connection resistance along a string in order to bypass the branch.

Seems doable, but there needs to be a way for the user to tell liionpack when to open/close the branches. Is it acceptable to expect the user to muck about with the netlist directly? Then we could extend liionpack.solve to optionally accept a list of netlist, the length of which must be equal to the number of steps in the supplied pybamm.Experiment. Each netlist would then be used to solve the corresponding step in the experiment.

Perhaps there is a way to do this without putting the onus on the user to supply a new netlist for every step, but if so I can't see it.

run a simulation and save the results then generate a new netlist and instantiate the cell models from the previous results.

This to me seems like a more intuitive solution, though perhaps less performant? And it still requires the user to mess with the netlists directly.

However, as I understand it only 0D variables can be output from the simulation, which means a lot of state would be lost between steps. What is the reason only 0D variables can be output? Can we change that to allow spatially distributed output (which I believe pybamm already supports)?

I guess we'd just define some extra electronic components like switches etc but I don't really want to go too far down that route as I think we'd be reinventing the wheel a lot of the time when maybe in future we can leverage spice or something to do all the circuit solving

Agreed.

@TomTranter
Copy link
Collaborator

TomTranter commented May 11, 2022

I think at this point editing the netlist directly is acceptable because the netlist is not constrained to be a standard combination of parallel and series connections. For large packs that are constrained in this way is would be helpful to have a way of easily accessing specific connections between cells. This would involve implementing some more advanced graph notation or classes for the netlist which is currently just a dataframe but is not a bad idea because any more complex thermal simulations than we currently have will need this anyway for cell to cell connections that are not electrical. I am working on some changes to the backend to enable this but my time is quite limited right now. This is why I asked @HongRi0716 whether they are academic or industry. Same goes for you @bessman? If there is functionality you need pybamm team to develop we will soon be forming a consultancy company that can be contracted to do it.

@bessman
Copy link

bessman commented May 12, 2022

I'm in industry.

@TomTranter
Copy link
Collaborator

@bessman 0D variables are output automatically and this was done for efficiency and simplicity. We could create an option to save the whole solution for each battery but this will quickly grow in memory for large packs

@wigging
Copy link
Collaborator

wigging commented Jul 19, 2022

I can change the resistance of a single branch by updating the Rc0 value in the netlist dataframe as shown below. Results show a cell current near zero and a constant cell voltage near 3.75 V.

# Change Rc0 branch resistance to bypass cell
netlist.at[2, 'value'] = 10

@Mingzefei
Copy link

We are just going to use reinforcement learning for reconfigurable batteries to achieve cell balancing. We are trying to establish a simulation environment for reconfigurable batteries, possibly through Python or MATLAB.

@HongRi0716 @bessman Hi! I am trying it, too. Have you finished this yet? I'm interested in your final method.

@bessman
Copy link

bessman commented Oct 17, 2023

I haven't looked at it further, sorry.

@TomTranter
Copy link
Collaborator

@Mingzefei I think @wigging suggestion about simply increasing the resistance of branches you want to switch off between steps should work without any code changes.

@Mingzefei
Copy link

I think @wigging suggestion about simply increasing the resistance of branches you want to switch off between steps should work without any code changes.

Yes, I spent some time implementing the swithes today.
Here is the specified reconfigurable structure and the code I write.

I use Rtn1 present S_1; Rcni present S_2,3,4,5; Rcmi present S_6,7,8; Rcpi present S_9,10,11,12 and Rtp1 present S_13, here.

def setup_Visairo_circuit(Nb,Ri=5e-2,V=4.0,I=5):
    # 0. init from lp.setup_circuit
    R_busbar = 1.5e-3
    R_connection = 1e-2
    Np = Nb
    Ns = 1
    netlist = lp.setup_circuit(
        Np=Np, Ns=Ns,
        Rb=R_busbar, Rc=R_connection,
        Ri=Ri, V=V,
        I=I
    )
    # 1. change Rci to Rcni ("desc")
    for i in range(Np):
        netlist.loc[netlist["desc"] == f"Rc{i}","desc"] = f"Rcn{i}"
    # 2. add Rcmi
    for i in range(Np-1):
        elem = {
            "desc" : f"Rcmi{i}",
            "node1" : Np * 1 + 1 + i,
            "node2" : Np * 3 + 2 + i,
        }
        netlist.loc[len(netlist)] = elem
    # 3. move up Rbpi, Rtp1 and I0
    elem_wait_move = ["Rtp1"] + [f"Rbp{i}" for i in range(Np-1, 2*Np-2)]
    node_wait_move = (netlist["node1"] > Np*3) & netlist["desc"].isin(elem_wait_move)
    netlist.loc[node_wait_move,"node1"] += Np
    netlist.loc[node_wait_move,"node2"] += Np
    netlist.loc[netlist["desc"] == "I0","node1"] += Np
    # 4. add Rcpi
    for i in range(Np):
        elem = {
            "desc" : f"Rcp{i}",
            "node1" : Np * 4 + 1 + i,
            "node2" : Np * 3 + 1 + i,
        }
        netlist.loc[len(netlist)] = elem
    # 5. update node_x and node_y
    def get_node_pos(node, Nc, Nr):
        total_node = Nc * Nr + 1
        if node == 0:
            return -1, 0
        if node == total_node:
            return -1, Nr-1
        pos_x = (node-1) % Np
        pos_y = (node-1) // Np
        return pos_x, pos_y
    Nc = Np
    Nr = Ns * 4 + 1
    netlist["node1_x"] = netlist["node1"].apply(lambda x: get_node_pos(x, Nc, Nr)[0])
    netlist["node1_y"] = netlist["node1"].apply(lambda x: get_node_pos(x, Nc, Nr)[1])
    netlist["node2_x"] = netlist["node2"].apply(lambda x: get_node_pos(x, Nc, Nr)[0])
    netlist["node2_y"] = netlist["node2"].apply(lambda x: get_node_pos(x, Nc, Nr)[1])

    def reconfigure(switch_state_list):

        def resistance_for_switch(switch_state):
            if switch_state == 1: # close
                return 1e-3
            else: # open
                return 1e3        
    
        # 1. reset Rtn1 value
        netlist.loc[netlist["desc"] == "Rtn1","value"] = resistance_for_switch(switch_state_list[0])
        # 2. reset Rcni value
        for i in range(Np):
            netlist.loc[netlist["desc"] == f"Rcn{i}","value"] = resistance_for_switch(switch_state_list[1+i])
        # 3. reset Rcmi value
        for i in range(Np-1):
            netlist.loc[netlist["desc"] == f"Rcmi{i}","value"] = resistance_for_switch(switch_state_list[1+Np+i])
        # 4. reset Rcpi value
        for i in range(Np):
            netlist.loc[netlist["desc"] == f"Rcp{i}","value"] = resistance_for_switch(switch_state_list[2*Np+i])
        # 5. reset Rtp1 value
        netlist.loc[netlist["desc"] == "Rtp1","value"] = resistance_for_switch(switch_state_list[3*Np])
        
        return netlist
        
    return reconfigure

It can be used like:

rbs_v = setup_Visairo_circuit(4)
print('open all switches')
print(rbs_v([0 for i in range(3*4+1)]))
print('close all switches')
print(rbs_v([1 for i in range(3*4+1)]))

However, three issues remain to be addressed:

  1. how to keep batteries' states after the structure reconfigured?
  2. the voltages and currents solved by liionpack are still currect, even for more complex structures? I have not checked it.
  3. function draw_circuit cannot draw the circuit rbs_v well. I got this error RuntimeError: The horizontal schematic graph has a loop.

Looking forward to your suggestions or opinions.

@TomTranter @wigging

@Mingzefei
Copy link

I did some tests today and found that the above solution did not achieve the expected results. So, I may try other tools like simulink later.
Anyway, I'm still looking forward to someone sharing the implementation of reconfiguration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants