Skip to content

Commit 33f17e7

Browse files
committed
symmetric problems post processing routines finished
tri2full() and buildRES() functions were added as a complement in vectfit3.py module. These functions are useful when processing fitting results of symmetric matrix functions.
1 parent 0123e26 commit 33f17e7

3 files changed

Lines changed: 55 additions & 35 deletions

File tree

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ The vector fitting function has many options that can be modified via _opts_ dic
4141
Default options of vector fitting are already defined into vectfit3.py module. There, _opts_ dictionary contains the following configuration:
4242

4343
opts={
44-
"lowert_mat" : False, # F(s) samples belong to a full matrix
44+
"symm_mat" : False, # F(s) samples belong to a full matrix
4545
"relax" : True, # Use vector fitting with relaxed non triviality
4646
"stable" : True, # Enforce stable poles
4747
"asymp" : 2, # Include only D in fitting (not E).
@@ -135,21 +135,24 @@ In the following figures vector fitting results for some test cases are shown:
135135
* Differences between _vectfit3.py_ and the original MATLAB implementation are listed below:
136136

137137
- All options for _vectfit3_ configuration are defined as boolean variables, except asymp which has 3 possible states.
138-
- The new option "lowert_mat" for _vectfit3_ configuration is added. This indicates when $F(s)$ samples belong to a lower triangular matrix function, that reduces the number of elements to fit for a symmetric matrix function.
138+
- The new option "symm_mat" for _vectfit3_ configuration is added. This indicates when $F(s)$ samples belong to a symmetric matrix function in CMO. This is a common practice because it reduces the number of elements to fit. See test 4
139139
- A new method to sort the poles computed during the identification process is implemented.
140140
- Real and complex data is meticulously treated and differentiated through the entire process.
141141
- General code organization.
142142
- A new method to compute error plots is implemented. The new error is $log_{10}(error_{relative})$
143143
- Error graphs are now plotted outside the magnitude axis as a subplot in the same figure.
144+
- Now "cmplx_ss" and "symm_mat" flags are also members of SER "dictionary". This is helpful when using the space-state model in external post-processing routines.
145+
- ss2pr() subroutine is renamed as buildRES() and is modified to return just the residues matrixes, because poles are already given by vectfit() main function.
146+
- tri2full subroutine, which is used to transform compressed results of a symmetric problem, is now internally called from buildRES() prior to compute residue matrixes. However can be imported from the module if it is needed.
144147

145148
### In development
146149
Nowadays, some final details in _vectfit3.py_ are still in progress:
147-
* The function _"buildPOLRES()"_, to build the poles and residues model from the state-space model generated by vector fitting needs to be finished.
148-
* Cases for symmetric problems that are represented with lower triangular matrixes need to be reconstructed to obtain a full state-space o pole-residue model.
150+
* _"buildRES()"_ function that computes residues matrixes from SER, only considers symmetric data reduction. Therefore a subroutine to map the results from element-wise representation "vectfit default" to a full matrix representation, when original data belong to a non-symmetric matrix function must be created. This function should take into account the mapping method used, for instance Column Major Order (CMO) and Row Major Order (RMO).
149151

150152
To contribute, give suggestions or report any bug please contact me:
151153
* Sebastian Loaiza Elejalde
152154
- _Dsc Student in Power Systems_
155+
- [_CINVESTAV - GDL_](https://unidad.gdl.cinvestav.mx/)
153156
- sebloel18@gmail.com 📬
154157
- sebastian.loaiza@cinvestav.mx 📬
155158

vectfit3.py

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
# Dictionary which contains the default settings fot vectfit.
6565
# Any key can be modified to change som options included in vectfit3
6666
opts={
67-
"lowert_mat" : False, # Indicates when F(s) samples belong to a lower triangular matrix (symmetric problem)
67+
"symm_mat" : False, # Indicates when F(s) samples belong to a lower triangular matrix (symmetric problem)
6868
"relax" : True, # Use vector fitting with relaxed non triviality
6969
"stable" : True, # Enforce stable poles
7070
"asymp" : 2, # Include only D in fitting (not E). See [4]
@@ -280,7 +280,7 @@ def vectfitPlot(F,fit,s,opts,initialState=False):
280280
plt.show()
281281

282282
# vectfit3() subroutine.
283-
def buildSER(Ac,Br,Cc,Dr,Er,cmplx_ss,lowert_mat=False):
283+
def buildSER(Ac,Br,Cc,Dr,Er,cmplx_ss,symm_mat):
284284
"""Function to build the state-space model of the fitted function such as:
285285
F(s) = C * (sI-A)^-1 * B + D + sE
286286
@@ -292,13 +292,13 @@ def buildSER(Ac,Br,Cc,Dr,Er,cmplx_ss,lowert_mat=False):
292292
- D: Constant terms matrix. Real matrix of shape [Nc x 1]
293293
- E: Proportional terms matrix. Real matrix of shape [Nc x 1]
294294
- cmplx_ss: Boolean option from opts{} which indicates if a complex system is needed
295-
- lower_mat: Boolean option from opts{} which indicates if data comes from a symmetric problem
295+
- symm_mat: Boolean option from opts{} which indicates if data comes from a symmetric matrix problem
296296
297297
Results.
298298
299299
- SER: Dictionary that storages A,B,C,D,E system matrixes adapted as indicated by cmplx_ss
300300
"""
301-
SER=dict(A=Ac,B=Br,C=Cc,D=Dr,E=Er,cmplxType=True,symmData=lowert_mat) #complex state-space system
301+
SER=dict(A=Ac,B=Br,C=Cc,D=Dr,E=Er,cmplx_type=True,symm_mat=symm_mat) #complex state-space system
302302
if not(cmplx_ss):
303303
# Real state-space system is required so the matrixes are modified
304304
Ar=np.real(Ac) #importing real poles to Ar
@@ -325,7 +325,7 @@ def buildSER(Ac,Br,Cc,Dr,Er,cmplx_ss,lowert_mat=False):
325325
SER["A"]=Ar
326326
SER["B"]=Br
327327
SER["C"]=Cr
328-
SER["cmplxType"]=False
328+
SER["cmplx_type"]=False
329329
return SER
330330

331331
# build_RES() subroutine.
@@ -344,24 +344,22 @@ def tri2full(SER, real2cmplx=False):
344344
C=SER["C"]
345345
D=SER["D"]
346346
E=SER["E"]
347-
if real2cmplx and A.dtype==np.float64: # Real to complex transformation is required
347+
if real2cmplx and not(SER["cmplx_type"]): # Real to complex transformation is required
348348
# Complex versions of A and C matrixes:
349349
Ac=np.zeros(A.shape, dtype=np.complex128)
350350
Cc=np.zeros(C.shape, dtype=np.complex128)
351-
# For complex poles B is a vector of ones:
352-
B=np.ones(B.shape, dtype=np.float64)
353-
for m in range(A.shape[0]-1):
354-
if A[m,m+1]!=0: #case for complex poles
355-
Ac[m,m]=A[m,m]+1j*A[m,m+1] #reference pole
356-
Ac[m+1,m+1]=A[m+1,m+1]-1j*A[m,m+1] #conjugated pole
357-
#ERROR BUILDING C complex
358-
Cc[:,m]=C[:,m]+1j*C[:,m+1] #Reference C value
359-
Cc[:,m+1]=np.conj(Cc[:,m]) #Conjugated C value
360-
else: #case pure real poles
351+
for m in range(A.shape[0]):
352+
if B[m,0]==1: #case for pure real poles
361353
Ac[m,m]=A[m,m]
362354
Cc[:,m]=C[:,m]
363-
#Updating A and C with their complex forms:
355+
elif B[m,0]==2: #case for complex poles
356+
Ac[m,m]=A[m,m]+1j*A[m,m+1] #reference pole
357+
Ac[m+1,m+1]=A[m+1,m+1]+1j*A[m+1,m] #conjugated pair
358+
Cc[:,m]=C[:,m]+1j*C[:,m+1]
359+
Cc[:,m+1]=np.conj(Cc[:,m])
360+
#Updating arrays with their complex forms:
364361
A=Ac
362+
B=np.ones(B.shape, dtype=np.float64) #for complex poles B is a vector of ones
365363
C=Cc
366364
# Unzip process parameters:
367365
n=B.shape[0] # Order of approximation
@@ -400,20 +398,34 @@ def tri2full(SER, real2cmplx=False):
400398
SER["C"]=Cf
401399
SER["D"]=Df
402400
SER["E"]=Ef
403-
SER["symmData"]=False
401+
SER["symm_mat"]=False
404402
return SER
405403

406404
def buildRES(SER):
407405
"""Function to generate the residues matrix of the fitted function computed by vectfit
408-
*Returns a tuple with:
409-
- R: residue matrixes stacked as a 3D array of shape [Ny x Ny x n]. Ny is the matrix function size and n the aproximation order
406+
*Returns residues matrixes stacked in Res:
407+
- Res: a 3D array of shape [Ny x Ny x n]. where Ny is the matrix function size and n the aproximation order
410408
"""
411409
# state-space model matrixes in SER:
412410
n=SER["A"].shape[0] # order of aproximation
413-
if SER["symmData"] and not(SER["cmplxType"]):
411+
if SER["symm_mat"]:
414412
# Data needs to be resized to a full matrix representation instead of lower trinagular and element-wise representation
415413
#and also the space-state model needs to be converte to a complex
416414
SER=tri2full(SER, real2cmplx=True)
415+
C=SER["C"]
416+
B=SER["B"]
417+
Ny=C.shape[0]
418+
Res=np.zeros((Ny,Ny,n), dtype=np.complex128) #Residues matrixes
419+
Rk=np.zeros((Ny,Ny), dtype=np.complex128) #Instant Res values
420+
i=0 # auxiliar index
421+
for k in range(n):
422+
Rk[:,:]=0
423+
for m in range(Ny):
424+
i=m*n+k
425+
#in order to perform the correct matrix operation C and B values must be reshaped
426+
Rk+=np.reshape(C[:,i],(Ny,1))@np.reshape(B[i,:],(1,Ny))
427+
Res[:,:,k]=Rk
428+
return Res
417429

418430
# * ---------------------------------------------------------- main vectfit3 function ---------------------------------------------------------- *
419431

@@ -833,7 +845,7 @@ def vectfit(F,s,poles,weights,opts=opts):
833845
C=SERC
834846
D=SERD
835847
E=SERE
836-
SER=buildSER(A,B,C,D,E,opts["cmplx_ss"],opts["lowert_mat"])
848+
SER=buildSER(A,B,C,D,E,opts["cmplx_ss"],opts["symm_mat"])
837849

838850
# Vector fitting process finished.
839851
return (SER,poles,rmserr,fit)

vectfit_testing.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
print(" v/ Fitting process completed. Aproximation error achieved = ",rmserr)
4848
print("\nFinal poles computed:\n",poles)
4949

50+
5051
elif test==2:
5152
print("Test 2: 18th order frequency response F(s) of two dimentions") # -------------------------------------------------------------------- #
5253

@@ -252,12 +253,13 @@
252253

253254
# vector fitting configuration
254255
from vectfit3 import opts
255-
opts["asymp"]=3 # Modified to include D and E in fitting
256-
opts["logx"]=False # Modified to use linear axis for x
257-
opts["spy2"]=False # Modified to omit graphs generation into the iterative application of vectfit
258-
opts["phaseplot"]=True # Modified to include the phase angle graph in the results
259-
opts["skip_res"]=True # Modified to skip residue computation during the iterative execution of vector fitting
260-
opts["cmplx_ss"]=False
256+
opts["asymp"]=3 # Modified to include D and E in fitting
257+
opts["logx"]=False # Modified to use linear axis for x
258+
opts["spy2"]=False # Modified to omit graphs generation into the iterative application of vectfit
259+
opts["phaseplot"]=True # Modified to include the phase angle graph in the results
260+
opts["skip_res"]=True # Modified to skip residue computation during the iterative execution of vector fitting
261+
opts["symm_mat"]=True # Modified to indicate that F(s) samples belong to the symmetric matrix Y(s)
262+
opts["cmplx_ss"]=False # Modified to create a real only space-state model
261263
# Remaining options by default
262264

263265
print("\n * Applying 5 iterations of vector fitting...")
@@ -284,6 +286,9 @@
284286
print(" ...",itr+1," iterations applied")
285287
print(" v/ Fitting process completed. Aproximation error achieved = ",rmserr)
286288
print("\nFinal poles computed:\n",poles)
287-
from vectfit3 import tri2full
288-
SER=tri2full(SER, real2cmplx=True)
289-
print("\nExpanded SER matrix = \n",SER["C"])
289+
290+
from vectfit3 import buildRES
291+
Res=buildRES(SER)
292+
print("\nResidues matrixes computed:\n")
293+
for k in range(n):
294+
print("\n",Res[:,:,k],"\n")

0 commit comments

Comments
 (0)