So far in this course, you have learned derivations for different methods to estimate battery cell total capacity. Now our focus is going to shift to learning how to implement these methods in Octave code and to gaining insight into how well they work using some simulation examples with that code. I have created a function in Octave that I call xLSalgos.m. This function computes total capacity estimates and confidence intervals on those estimates using the different methods that you have learned about in this course. In this lesson, I am going to share with you the details of this function and how it is implemented. Then later lessons this week, I will share with you how to invoke this function for different scenarios to try different experiments. So, let's begin. I share with you here the comments that are at the very beginning of the xLSalgo.m function. These comments tell the user what the expected input parameters are and what the outputs from the function r as well. So, this function expects vector of measured X values and a vector of measured Y values and vectors of variances on both of these, a scalar forgetting factor and nominal capacity to use for initializing the algorithms and a variance of cell capacities at beginning of life also to be used for initializing the algorithms. The nominal capacity can be specified as its true value or a zero. If the capacity is specified as zero, then the parameters for the recursive methods will be initialized simply to zero. Otherwise, they will be initialized using the method that we talked about in previous weeks that had a synthetic zeroth measurement. The final input to this function, the sigma Y zero input is optional, but if it is specified, it will be used when initializing the recursive parameters as you will see. There are two outputs from this function. The first output is a matrix of capacity estimates. Each column of this matrix corresponds to the output of one of the four different methods that this function computes. The first column is for the weighted least squares method. The second, the weighted total least-squares method. The third is the simplified total least-squares method, and the final is the AWTLS or approximate weighted total least-squares method. The second output from the function is a matrix of variances on these estimates, and the elements for this matrix correspond one to one with the elements from the capacity estimate matrix. So, the matrix of variances can be used to compute error bounds on the capacity estimates. The function begins by initializing the different methods. In the first line, I convert all of the input vectors into column vectors in case they are not already in that format. In the second line, I reserve some storage for the output matrices. In the third line, I compute the proportionality constant of uncertainty between X and Y. This is used by the AWTLS method to scale the Y inputs to create internal to this function Y tilde inputs, as we discussed late last week. The recursive parameters are first initialized to a default value of zero. The lower case variables are for standard unscaled recursive parameters, and the uppercase variables are used by the AWTLS method and they use the scaled version of letter Y converted to Y tilde inside of their computations. The input Qnom is interrogated. If it's equal to zero, then all of the recursive parameters remain initialized to zero. But if a nominal capacity is supplied, the recursive parameters are reinitialized based on synthetic first measurement, where X is zero equals one and Y zero is equal to this nominal capacity value. For this initialization, the user may provide an optional input signal Y zero, or the method can simply use the first element of the sigma Y vector instead. The recursive parameters are initialized exactly as described last week. This particular function is organized to take in all of the X data points and all of the Y data points and operate on these vectors one data point, one element at a time. So, the first thing that we do is we enter a loop that iterates through all of these input data points one at a time and makes updates to the capacity elements one at a time based on the data measured from the initial point in time up to the Kth point in time. So, at the beginning of the loop, we first update the unscaled recursive parameter values as you learned about, and then we update the scaled parameter values as well. The code then computes updates to the total capacity estimates for all of the data up to and including this particular timestamp in the loop using each one of the four methods. We start by computing a capacity estimate using the weighted least-squares method. This is the simplest of all of the methods where capacity is computed as c2 divided by c1 and the Hessian is computed as two times c1. So, the capacity and the variance are both stored in the first column of the output matrices in the row corresponding to this particular iteration through the data vectors that were provided as input to this function. Second, we implement the weighted total least-squares method. Remember that this method is not recursive and so instead of using the recursive parameters, we need to use all of the input data up to and including the data measured at this iteration inclusive for updating the total capacity. I first make a new variable X which contains all of the X data up until this point in time, I make a new variable Y, and I make variables SX and SY for the variances on X and Y. I also make a vector G, which is the forgetting factor raised to different powers, such that the weighting of the present sample is equal to gamma to the zero or one, and the weighting of the previous sample is equal to gamma to the one or just gamma, and an earlier samples are simply gamma to greater powers which result in smaller values for the waiting constants. Remember that we need to use a numeric solution to find the weighted total least-squares answer and we need to initialize this numeric solution. Here I choose to initialize it to the estimate of capacity that was produced by the weighted least-square solution just a moment ago. Then, we enter a Newton-Raphson update where we repeatedly compute the Jacobian J and the Hessian and H of the cost function and the new capacity is estimated as the previous capacity minus J divided by H. Within about five iterations, this Newton-Raphson method should converge to a good solution providing that the input data are consistent. So, we store the capacity estimate, and the variance estimate, and the output matrices. Sometimes, I find that the initial estimates of the weighted total least-squares method do not converge, which goes against what we believe to be guaranteed by the theory of the problem. I believe that is true because the input data are sometimes not consistent if there's a lot of noise on the data. So, the signs of X and Y should both be positive if I remember correctly and maybe one is negative because of the numeric noise that's added. So, these cases, the WTLS method may not converge. In those cases, I assign an output of NaN, which stands for "not a number" to the capacity estimate and I assign values of zero to the variance, so that the function that is calling this routine can then understand, don't use that value of total capacity, wait until later until the capacity is reliable. So, again, I've not explored in detail anyway why this does not converge. I believe it does not converge because of the reason that I have suggested. And it's possible, in that case, that we can improve the situation by taking absolute values of X and Y before executing this function. I have not explored that. That might be something that you could explore to see if that does help those situations. The code on this slide then implements the simplified TLS solution and this is a recursive method. You might remember that capacity is computed as the root of a quadratic equation. So, the first line of code on this slide computes that quadratic solution and then the next part of code computes the Hessian and stores the capacity estimate and the variance. Finally, the code on this slide implements the approximate weighted total least-squares method using recursive parameters. Remember that this method requires finding the roots of a fourth order polynomial or a quartic equation. We might attempt to use some method like a Ferrari method or a Descartes' method to do that. But I shared with you earlier that I found that these closed four methods tend to be fragile numerically and the small round-off errors in the floating point math result in very large output errors. So, for some input values, I found that the Ferrari method, for example, can work very well but for others, it really doesn't. So, here instead, I use the roots command in Octave, which I believe is based on finding the eigenvalues of a matrix that's called a companion matrix, in order to find the four solutions of the quartic equation. The second line then keeps only the roots that are entirely real and discards any roots that have imaginary components. The third line discards any roots that have negative value, and the fourth line computes the AWTLS cost function with any remaining roots, then it finds which one is the minimum and that root that provides the minimum cost is the one that is stored in the output matrix. The Hessian is also computed and stored. That brings us to the end of AWTLS method, and indeed, the end of this loop that goes through all of the input data. When the loop is complete, the function returns its estimates and variances to the user. So, in summary, you've now learned how to implement each one of these different total capacity estimators in Octave. The implementation of the weighted least-squares method was very straightforward using recursive parameters. The weighted total least-squares method is not recursive and so it's somewhat more difficult to implement and requires that all of the data up until the present point in time is reevaluated every iteration through the loop. The TLS method is recursive and it's almost as simple to implement as the weighted least-squares method. The AWTLS method is recursive as well, that requires finding the roots have a quartic equation. This is more challenging to do in an embedded system where you must probably locate a library that computes these roots for you, but it's very simple to do in Octave because that library is built-in to the main Octave code. The AWTLS solution is also more challenging because we must determine which one of the four roots is the optimum, but you've seen that it's really not that difficult to do after all. So, that brings us to the end of this lesson. In the remaining lessons this week, you will learn how to develop different scenarios to exercise this function, these algorithms to produce estimates of total capacity so that you can gain some intuition regarding how those different methods perform as compared to each other.