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

filter transfer function not correct at high frequencies #242

Open
lneuhaus opened this issue Apr 20, 2017 · 5 comments
Open

filter transfer function not correct at high frequencies #242

lneuhaus opened this issue Apr 20, 2017 · 5 comments
Assignees

Comments

@lneuhaus
Copy link
Collaborator

question is: is this a filter artifact or a NA artifact
-> i have corrected the filter transfer function for the warping effect, but this effect is usually (even at 10 MHz) quite negligible

this still reproduces the error

lp=2.5e6
p.networkanalyzer.setup(start_freq=1e4, stop_freq=10e6, points = 51, rbw = 500, input='pid0', logscale=True)
p.rp.pid0.setup(p=1, i=0, input=p.networkanalyzer.iq, inputfilter = [lp,lp,lp,lp])
cu = p.networkanalyzer.curve()
f = p.networkanalyzer.data_x
th = p.rp.pid0.transfer_function(f)
semilogx(f,abs(cu)**2, label="measure")
semilogx(1.2*f,0.98*abs(th)**2, label="theory with scaling factor")
semilogx(f,0.98*abs(th)**2, label="theory unmodified")
legend()
@lneuhaus
Copy link
Collaborator Author

lneuhaus commented Apr 20, 2017

image

Code:

lp=2.5e6
p.networkanalyzer.setup(start_freq=1e4, stop_freq=10e6, points = 51, rbw = 500, input='pid0', logscale=True)
p.rp.pid0.setup(p=1, i=0, input=p.networkanalyzer.iq, inputfilter = [lp, lp, lp, lp])
cu = p.networkanalyzer.curve()
f = p.networkanalyzer.data_x
th = p.rp.pid0.transfer_function(f)
app = " with 4 lps"
semilogx(f,abs(cu)**2, label="measure"+app)
semilogx(1.2*f,0.98*abs(th)**2, label="theory with scaling factor"+app)
semilogx(f,0.98*abs(th)**2, label="theory unmodified"+app)
legend()

@lneuhaus
Copy link
Collaborator Author

image

NA is not the problem: measurement with a 2000 Hz integrator works well


lp=0.e6
p.networkanalyzer.setup(start_freq=1e4, stop_freq=10e6, points = 51, rbw = 500, input='pid0', logscale=True)
p.rp.pid0.setup(p=1*0, i=2000, input=p.networkanalyzer.iq, 
                #inputfilter = [lp, lp, lp, lp])
                inputfilter = [lp])
p.rp.pid0.ival=0
cu = p.networkanalyzer.curve()
f = p.networkanalyzer.data_x
th = p.rp.pid0.transfer_function(f)
app = " with 2000 Hz integrator"
loglog(f,abs(cu)**2, label="measure"+app)
loglog(1.2*f,0.98*abs(th)**2, label="theory with scaling factor"+app)
loglog(f,0.98*abs(th)**2, label="theory unmodified"+app)
legend()

@lneuhaus
Copy link
Collaborator Author

I still dont see what causes this behavior. No decimation is performed. The problem only occurs for the two highest bandwidth values 5 and 10 MHz which are almost never used in practice. The new unittest should guarantee that this will not cause problems in the future, despite the empirical solution. Still would be nice to find the reason for this

@SamuelDeleglise
Copy link
Collaborator

To be complete, I paste my code, and the produced figure for the first order filter. Things look not as simple as just a modified cutoff frequency when plotting up to nyquist frequency. Are we trying to put a dirty manual correction of the transfer function in the current release or do we keep the small discrepency until we really understand the problem ? (I would be in favor of the latter)

pids_problem

close('all')
figure()

bws = [1e4, 1e5, 1e6, 2e6, 4e6]
for index, bw in enumerate(bws):
    p.networkanalyzer.setup(rbw=bw/10, 
                            points=1000, 
                            logscale=True, 
                            start_freq=bw/3, 
                            stop_freq=125e6/2, 
                            input='pid0',
                            avg_per_point=3,
                            avg=1)
    p.rp.pid0.setup(inputfilter=bw,
                    input=p.networkanalyzer.iq,
                    p=1, i=0,d=0)
    curve = p.networkanalyzer.single()
    freqs = p.networkanalyzer.data_x
    nu = p.networkanalyzer.data_x
    #nu2 = 125e6/(4*pi)*tan(2*pi*nu*2/(125e6))
    theory = p.rp.pid0.transfer_function(freqs)

    col = color=cm.cool(index/len(bws))
    sub = subplot(211)
    plot(freqs, abs(curve)**2, color=col, label='measured(bw=%.3e)'%bw)
    plot(freqs, abs(theory)**2,":", color=col, label='theory(bw=%.3e)'%bw)
    ylabel('square mag.')
    gca().set_yscale('log')
    gca().set_xscale('log')

    subplot(212, sharex=sub)
    plot(freqs, angle(curve), color=col, label='measured(bw=%.1e)'%bw)
    plot(freqs, angle(theory),":", color=col, label='theory(bw=%.1e)'%bw)
    ylabel('phase')
    #gca().set_yscale('log')
    gca().set_xscale('log')


legend()
xlim(1e5, 125e6/2)
savefig('pids_problem.png')

@lneuhaus
Copy link
Collaborator Author

on my branch (develop-0.9.3) there is already the dirty fix including a unittest (but i have never actually run the test so far). If you would like to, you can pull from the branch and try it out. I could analytically model the highest cutoff frequency, but it did not make sense.
The way i did that was to use a first order digital filter with numerator coefficient alpha and denominator coefficients 1 and -(1-alpha), with a value alpha=0.5 for the 5 MHz cutoff lowpass, and to square the frequency response computed with scipy's freqz (squaring twice for the response in dB, i.e. imitating a second-order filter). The expected value for alpha was 0.25, and no squaring should have been needed. Other cutoff frequencies could not be modeled like that. I actually suspect that there is a timing problem in the fpga, such that denominator coefficients are delayed by one cycle or so, giving a second-order filter response at the highest frequencies. Therefore, I suggest we keep the dirty solution for now and wait for the unittest to fail once the FPGA timing is optimized..

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

No branches or pull requests

2 participants