Frequency Domain Inversion
From Wikimization
(Difference between revisions)
(New page: <pre> %computation of mapping coefficients by frequency domain inversion. August 9 2023 %this subroutine is used for thd+n measurements only; single test tone. function [zeta lp_failure] =...) |
|||
(One intermediate revision not shown.) | |||
Line 14: | Line 14: | ||
end | end | ||
mp.Digits(precision); | mp.Digits(precision); | ||
- | if numel(theta) == 1 | + | if numel(theta) == 1 %preferably nonlinearity output fundamental phase |
theta = (1:Nh)'*theta; %linear phase | theta = (1:Nh)'*theta; %linear phase | ||
elseif isrow(theta) | elseif isrow(theta) | ||
Line 91: | Line 91: | ||
lp_failure = true; | lp_failure = true; | ||
end | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | %adjust mapping coefficients for unity gain | ||
+ | function xi = ug(xi, Ep, precision) | ||
+ | version -blas; version -lapack; %load AMD AOCL libraries | ||
+ | if nargin < 3 | ||
+ | precision = 34; | ||
+ | end | ||
+ | mp.Digits(precision); | ||
+ | zero = mp('0'); | ||
+ | one = mp('1'); | ||
+ | two = mp('2'); | ||
+ | Nh = numel(xi); | ||
+ | t = zero; | ||
+ | for n=2:ceil(Nh/2) | ||
+ | t = t + nchoosek(two*n-one,n-one)*(Ep/two)^(two*n-two)*xi(2*n-1); | ||
+ | end | ||
+ | xi(1) = one - t; %adjust for unity gain. | ||
+ | if xi(1) < 0 | ||
+ | xi(3:2:Nh) = -xi(3:2:Nh); %negativity check | ||
+ | xi(1) = one + t; | ||
end | end | ||
end | end | ||
</pre> | </pre> |
Current revision
%computation of mapping coefficients by frequency domain inversion. August 9 2023 %this subroutine is used for thd+n measurements only; single test tone. function [zeta lp_failure] = backsubzfreq(Ep, E, fn, Nh, theta, precision) %fn is complex conjugate data 2*conj(fft)/N. version -blas; version -lapack; %load AMD AOCL libraries maximallyflat = ~true; %theta is vector or scalar [rads] modifying twiddle W closed = true; %closed form solution. nonclosed is for backsubz3Test (thd); linprog prone to failure for small amplitude test tone or high Nh matrix_Inversion = ~true; %choose closed form method: matrix inversion or analytical inverse unitygainconstraint = ~true; %amplitude Ep used for unity gain xi determination. E used only to make twiddle matrix. lorenzo = ~true; %Lorenzo David closed form twiddle matrix. if size(fn,1) ~= Nh, disp(' ');disp('backsubzfreq(): fn length error');disp(' '); return; end if nargin < 6 precision = 34; end mp.Digits(precision); if numel(theta) == 1 %preferably nonlinearity output fundamental phase theta = (1:Nh)'*theta; %linear phase elseif isrow(theta) theta = theta'; end zero = mp('0'); one = mp('1'); two = mp('2'); W = zeros(Nh+1,Nh,'mp'); C = zeros(1,Nh,'mp'); %%% make real twiddle matrix if lorenzo for i=1:Nh for j=i:Nh if ~mod(i+j,2) W(i,j) = two*(E/two)^j*nchoosek(mp(j),(j-i)/two); %second binomial coefficient (i+j)/2 is equivalent to (-i+j)/2 because of numerator j end end end else for i=1:Nh k = 0; idx = i:2:Nh; for j=idx %binomial coefs C(j) = nchoosek(mp(j),mp(k)); k = k + 1; end W(i,idx) = two*(E/two).^idx.*C(idx); %E corresponds to measured signal amplitude in frequency domain fn end end if maximallyflat for n=2:ceil(Nh/2) W(Nh+1,2*n-1) = nchoosek(two*n-one,n-one)/two^(2*n-2); end theta = [theta; zero]; fn = [fn; zero]; else W(Nh+1,:) = []; end %%% mapping coef solution by closed form projection OR by linear algebraic inversion (linprog, simplex) lp_failure = false; if closed if matrix_Inversion zeta = real((exp(1j*theta).*W)\fn); else zeta = zeros(Nh,1,'mp'); %from "monotone frequency domain inversion" in chapter 8 for j=1:Nh % for k=j:floor((Nh+j)/two) % zeta(j) = zeta(j) + real((-one)^(k-j)*(two*k-j)*nchoosek(k-one,mp(k-j))*exp(-1j*theta(2*k-j))*fn(2*k-j)); % end for k=0:floor((Nh-j)/two) %Nov.24 2024 changing real to abs fails backsubz3Test.m % zeta(j) = zeta(j) + abs((two*k+j)*binomial(mp(-j),mp(k),precision)*exp(-1j*theta(2*k+j))*fn(2*k+j)); zeta(j) = zeta(j) + real((two*k+j)*binomial(mp(-j),mp(k),precision)*exp(-1j*theta(2*k+j))*fn(2*k+j)); end zeta(j) = two^(j-1)*zeta(j)/(j*E^j); %two^(j-1) because DFT already multiplied by 2 end end if unitygainconstraint zeta = ug(zeta, Ep, precision); %unity gain and negativity check end else Aeq = double([real(exp(1j*theta).*W) imag(exp(1j*theta).*W)]); beq = double([real(fn) imag(fn)]); if unitygainconstraint D = zeros(1,Nh); for n=1:ceil(Nh/2) D(1,2*n-1) = nchoosek(two*n-one,n-one)*(Ep/two)^(two*n-two); end Aeq = [Aeq; D]; beq = [beq; 1]; %unity gain constraint. end [zeta,~,flag] = linprog(ones(Nh,1), [], [], Aeq, beq, [0; -inf(Nh-1,1)]); %prone to failure for small amplitude test tone or high Nh if flag < 0 zeta = zeros(Nh,1,'mp'); lp_failure = true; end end end %adjust mapping coefficients for unity gain function xi = ug(xi, Ep, precision) version -blas; version -lapack; %load AMD AOCL libraries if nargin < 3 precision = 34; end mp.Digits(precision); zero = mp('0'); one = mp('1'); two = mp('2'); Nh = numel(xi); t = zero; for n=2:ceil(Nh/2) t = t + nchoosek(two*n-one,n-one)*(Ep/two)^(two*n-two)*xi(2*n-1); end xi(1) = one - t; %adjust for unity gain. if xi(1) < 0 xi(3:2:Nh) = -xi(3:2:Nh); %negativity check xi(1) = one + t; end end