How to reformat the display output precision of e.g. the TF() function?

33 views (last 30 days)
When asking for a transfer function, given a state-space object sysd, MATLAB prints the result like this:
>> tfd = tf(sysd)
tfd =
0.05563 z + 0.05568
----------------------
z^2 - 1.988 z + 0.9923
The precision used is insufficient for my purposes (I need more than 7 significant digits). It appears not to be possible to use e.g. "format long e" to change this?
Of course I can ask for tfd.num and tf.den and print these arrays with long e, but that is not very convenient (I like the pretty printed display and don't see an easy way to write that myself). How to instruct MATLAB to use the proper format in this case?
PS: There are more functions and figures that display data in difficult to change numeric formats or in ugly windows (like the Bode and pz diagrams from the control toolbox). It would be nice if one could change all that in a (semi-)permanent way.
  4 Comments
marcel hendrix
marcel hendrix on 7 May 2022
@Paul: > Or, in other words, why is seeing those extra few digits important?
Good question. My current way of working is that I copy the output of commands like this with the mouse and directly paste them into the application (here a SPICE netlist of a digital controller circuit). The formatted text then also serves as documentation where these numbers are coming from. This specific display does not only tell the value of the coefficients, but also if they belong in the numerator or denominator and to what power of 'z' they apply.
A few more digits may seem unimportant, however, for transfer functions only 5 significant digits for the polynomial coefficients can mean more than 1 Volt of DC offset in a steady state solution.

Sign in to comment.

Accepted Answer

Paul
Paul on 7 May 2022
Edited: Paul on 22 Oct 2022
EDIT 22 Oct 2022: Updated code to fix a bug where the leading coeficient of a polynomial is -1. followed by digits after the decimal point, in response to this comment
The function poly2str in the CST may be of interest, I think that the numerical formatting is governed by a single line, so I guess you could make a local copy and modify that line and go from there.
which poly2str
/MATLAB/toolbox/control/ctrlobsolete/poly2str.m
Here's my attempt. I have not fully tested it and so there may be (probably are!) some corner cases I haven't considered.
User beware.
It assumes a discrete time tf in the variable z. I'm sure it could be generalized.
rng(100);
tfd = tf(rand(1,3).*[-1 -1 1],rand(1,5).*[1 -1 1 -1 1],-1)
tfd = -0.5434 z^2 - 0.2784 z + 0.4245 ---------------------------------------------------------- 0.8448 z^4 - 0.004719 z^3 + 0.1216 z^2 - 0.6707 z + 0.8259 Sample time: unspecified Discrete-time transfer function.
localdisptf(tfd);
tfd = -0.5434049417909654 z^2 - 0.2783693850937962 z + 0.4245175907491331 ---------------------------------------------------------------------------------------------------------------------- 0.8447761323199037 z^4 - 0.004718856190972565 z^3 + 0.1215691207831142 z^2 - 0.6707490847267786 z + 0.8258527551050476
tfd = tf([-1 1],[1 -2.00000001 1],-1)
tfd = -z + 1 ------------- z^2 - 2 z + 1 Sample time: unspecified Discrete-time transfer function.
localdisptf(tfd);
tfd = -z + 1 ---------------------- z^2 - 2.00000001 z + 1
tfd = tf([-1],[-1 -1 1],-1)
tfd = 1 ----------- z^2 + z - 1 Sample time: unspecified Discrete-time transfer function.
localdisptf(tfd);
tfd = -1 ------------ -z^2 - z + 1
Matlab always displays with leading coeffficient of denominator positive. Code can be modfied if desired.
tfd = tf(1.000004,-5.31256,-1)
tfd = -0.1882 Static gain.
localdisptf(tfd);
tfd = 1.000004 -------- -5.31256
Matlab displays static gains as a single number. Code can be modified if desired.
This example was not handled correctly prior to the edit on 22 Oct 2022.
tfd = tf([-1.1 1],[-1.1 1 1],-1)
tfd = 1.1 z - 1 --------------- 1.1 z^2 - z - 1 Sample time: unspecified Discrete-time transfer function.
localdisptf(tfd)
tfd = -1.1 z + 1 ---------------- -1.1 z^2 + z + 1
Matlab enforces that leading coefficient on denominator is positive. Code can be modified if desired to follow that convention.
function polystr = localpolystr(polynomial)
% convert numerical coefficients to string representation
polystr = split(string(num2str(polynomial,16))); % change fmt as needed, or it can be a function input
% delete leading terms with coefficients of zero
firstnonzero = find(polystr~= "0",1);
polystr(1:firstnonzero-1) = [];
% append the z variable to each term, except z^0
for ii = 1:numel(polystr)-1
polystr(ii) = polystr(ii) + " z^" + string(numel(polystr)-ii);
end
% delete the ^1 from the z^1 term so it only displays as z
polystr = erase(polystr,"^1");
% find all the terms that have a negative coefficient
negativeterms = find(extractBefore(polystr,2) == "-");
% except the first term that will be treated separately
negativeterms(negativeterms == 1) = [];
% only keep the number after the negative sign for the negative coefficients
polystr(negativeterms) = extractAfter(polystr(negativeterms),1);
% + or - dividers between each term in the expression
dividers = ["" ; repmat(" + ",numel(polystr)-1,1)];
dividers(negativeterms) = " - ";
% don't show coefficient if it's 1
unityterms = find(extractBefore(polystr(1:end-1),3) == "1 ");
polystr(unityterms) = extractAfter(polystr(unityterms),2);
% special case for -1 leading coefficient of a polynomial
if numel(polystr) > 1 && strlength(polystr(1)) > 3 && extractBefore(polystr(1),4) == "-1 "
polystr(1) = "-" + extractAfter(polystr(1),3);
end
polystr = dividers + polystr;
polystr = join(polystr,"");
end
function localdisptf(htf)
% extract numerator and denominator
num = htf.num{1};
den = htf.den{1};
% convert to string representation
denstr = localpolystr(den);
numstr = localpolystr(num);
% create the fraction divider
divider = join(repmat("-",1,max(strlength(denstr),strlength(numstr))),"");
% center the numerator, divider, and denominator strings
tfstrings = strjust(pad([numstr;divider;denstr]),'center');
% display
disp(inputname(1) + " =")
disp(tfstrings(1));
disp(tfstrings(2));
disp(tfstrings(3));
end
  7 Comments
marcel hendrix
marcel hendrix on 23 Oct 2022
Dear Paul,
> BTW, given your application, would it be better to keep all the exact "1" coefficients explict in the display?
The text is pasted onto the SPICE netlist, mainly for documentation purposes. There is (MATLAB) code that extracts the sampled-data state matrix of a switching circuit from its impulse response (by curve-fitting). That code knows the num() and den() in full precision, but couldn't convert the coefficients to a pretty printed transfer function, until now :--)
There is no need to keep the exact "1"s, the present format reads nice for humans and allows them to insert the displayed coefficients by hand into a SPICE ZTF subcircuit (z-domain transfer function block). The main problem there is always which coefficient goes with what power of 'z'... Printing the TF as text makes that unambiguous.
Thanks again!
-marcel

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!