Subversion Repositories pentevo

Rev

Rev 1246 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1246 Rev 1248
Line 1... Line -...
1
#!/usr/bin/env python
-
 
2
 
-
 
3
import sys
-
 
4
from sympy import *
1
from sympy import *
5
import math
-
 
6
import cmath
-
 
7
import random
-
 
8
 
-
 
9
#e24 = [1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1];
-
 
10
#e6  = [1.0,                1.5,                2.2,                3.3,                4.7,                6.8               ];
-
 
11
 
-
 
12
 
-
 
13
 
-
 
14
def calc_mfb3_lowpass():
-
 
15
 
-
 
16
    # as in mfb3.png
-
 
17
 
2
 
18
    r1,r2,r3,r4,c1,c2,c3 = symbols('r1 r2 r3 r4 c1 c2 c3', real=True, positive=True)
3
r1,r2,r3,r4,c1,c2,c3 = symbols('r1 r2 r3 r4 c1 c2 c3', real=True, positive=True)
19
 
4
 
20
    ui,uo,u1,u2,u3 = symbols('ui uo u1 u2 u3')
5
ui,uo,u1,u2,u3 = symbols('ui uo u1 u2 u3')
21
 
6
 
Line 45... Line 30...
45
    eqs += [ Eq( u3, 0 ) ]
30
eqs += [ Eq( u3, 0 ) ]
46
 
31
 
47
    # solve the set
32
# solve the set
48
    u_solve = solve( eqs, [u1,u2,u3,ir1,ir2,ir3,ir4,uo], dict=True, domain=S.Complexes )
33
u_solve = solve( eqs, [u1,u2,u3,ir1,ir2,ir3,ir4,uo], dict=True, domain=S.Complexes )
49
 
34
 
50
    print(u_solve)
35
#print(u_solve)
51
 
36
 
52
    if len(u_solve)!=1:
37
if len(u_solve)!=1:
53
        sys.stderr.write("Many or no solutions: {} !\n".format(u_solve))
38
    sys.stderr.write("Many or no solutions: {} !\n".format(u_solve))
54
        exit(1)
39
    exit(1)
55
   
40
 
Line 57... Line 42...
57
 
42
 
58
    h_expr = u_expr[uo]/ui
43
h_expr = u_expr[uo]/ui
59
 
44
 
60
    print(h_expr)
45
print(h_expr)
61
 
46
 
62
    # now make more substitutions
-
 
63
    #
-
 
64
    h = symbols('h')
-
 
65
    k = symbols('k', real=True, negative=True)
-
 
66
    q,w1,w2 = symbols('q w1 w2', real=True, positive=True)
-
 
67
    #
-
 
68
    # filter gain
-
 
69
    s_eq1 = Eq( k, -r3/(r1+r2) )
-
 
70
    #
-
 
71
    # canonical H expr
-
 
72
    s_eq2 = Eq( h, k/( (1+(I*w)/w1) * (1+(I*w)/(q*w2)-(w*w)/(w2*w2)) ) )
-
 
73
    #
-
 
74
    # h through r/c
-
 
75
    s_eq3 = Eq( h, h_expr )
-
 
76
 
-
 
77
    # solve
-
 
78
    h_solve = solve( [s_eq1, s_eq2, s_eq3], [r1, r2, r3, r4, c1, c2, c3], dict=True )
-
 
79
 
-
 
80
    print(h_solve)
-
 
81
 
-
 
82
    sys.exit(0)
-
 
83
 
-
 
84
    if len(h_solve)!=1:
-
 
85
        sys.stderr.write("Many or no solutions: {} !\n".format(h_solve))
-
 
86
        exit(1)
-
 
87
 
-
 
88
    h_expr = h_solve[0]
-
 
89
    h_result = h_expr[h]
-
 
90
 
-
 
91
    init_printing()
-
 
92
    print('')
-
 
93
    #pprint(h_expr)
47
(n,d)=fraction(h_expr)
94
    print('')
-
 
95
    pprint(Eq(h,h_result))
-
 
96
 
-
 
97
 
-
 
98
    rc_solve = solve( [s_eq1, s_eq2, s_eq3], [r3,c2], dict=True )
-
 
99
 
-
 
100
    rc_expr = rc_solve[0]
-
 
101
 
-
 
102
    print('')
-
 
103
    pprint(Eq(c2,rc_expr[c2]))
-
 
104
    print('')
-
 
105
    pprint(Eq(r3,rc_expr[r3]))
-
 
106
    print('')
-
 
107
    pprint(s_eq1)
-
 
108
    print('')
-
 
109
    pprint(s_eq2)
-
 
110
    print('')
-
 
111
    pprint(s_eq3)
-
 
112
 
-
 
113
# these formulae calculated symbolically by the function above and are set here in comments
-
 
114
# as reference for further numerical calculations.
-
 
115
"""
-
 
116
         ____________
-
 
117
       ╲╱ c₁⋅c₂⋅r₂⋅r₃
-
 
118
q = ─────────────────────
-
 
119
     c₁⋅((1 - k)⋅r₃ + r₂)
-
 
120
 
-
 
121
            1            
-
 
122
wc = ───────────────
-
 
123
       ____________
-
 
124
     ╲╱ c₁⋅c₂⋅r₂⋅r₃
-
 
125
 
-
 
126
 
-
 
127
    -r₂
-
 
128
k = ────
-
 
129
     r₁
-
 
130
 
-
 
131
                  2        
-
 
132
            k⋅q⋅wc        
-
 
133
h = ───────────────────────
-
 
134
         2       2        
-
 
135
    - q⋅w  + q⋅wc  + ⅈ⋅w⋅wc
-
 
136
 
-
 
137
           q⋅(k - 1)      
-
 
138
c₂ = ──────────────────────
-
 
139
     r₂⋅wc⋅(c₁⋅q⋅r₂⋅wc - 1)
-
 
140
 
-
 
141
     c₁⋅q⋅r₂⋅wc - 1
-
 
142
r₃ = ───────────────
-
 
143
     c₁⋅q⋅wc⋅(k - 1)
-
 
144
 
-
 
145
"""
-
 
146
 
-
 
147
 
-
 
148
def select_pvalues_list(values='e24'):
-
 
149
# returns [1.0, ..., 9.1] list (for e24)
-
 
150
 
-
 
151
    if values=='e24':
-
 
152
        r = [1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1]
-
 
153
    elif values=='e12':
-
 
154
        r = [1.0,      1.2,      1.5,      1.8,      2.2,      2.7,      3.3,      3.9,      4.7,      5.6,      6.8,      8.2     ]
-
 
155
    elif values=='e6':
-
 
156
        r = [1.0,                1.5,                2.2,                3.3,                4.7,                6.8               ]
-
 
157
    else:
-
 
158
        sys.stderr.write('wrong argument given!\n')
-
 
159
        raise NameError('stop here')
-
 
160
        sys.exit(1)
-
 
161
 
-
 
162
    r = [r[-1]*0.1] + r + [r[0]*10.0]
-
 
163
 
-
 
164
    return r
-
 
165
 
-
 
166
 
-
 
167
 
-
 
168
 
-
 
169
def select_two_nearest(val,val_exp,pvalues_name='e24'):
-
 
170
 
-
 
171
    def my_lt(v1,v2):
-
 
172
        return (v1<v2) and (not math.isclose(v1,v2,rel_tol=1e-3))
-
 
173
 
-
 
174
    def my_gt(v1,v2):
48
d2=(d/n)*(-r3/(r1+r2))
175
        return (v1>v2) and (not math.isclose(v1,v2,rel_tol=1e-3))
-
 
176
 
-
 
177
 
-
 
178
    pvalues = select_pvalues_list(pvalues_name)
-
 
179
 
-
 
180
    # select range
-
 
181
    if my_lt(val, min(pvalues[1:-1])):
-
 
182
        while my_lt(val, min(pvalues[1:-1])):
-
 
183
            if my_lt(val, max(pvalues[1:-1])*0.1):
-
 
184
                val     = val     * 10.0;
-
 
185
                val_exp = val_exp *  0.1;
-
 
186
            else:
-
 
187
                break;
-
 
188
 
-
 
189
    elif my_gt(val, max(pvalues[1:-1])):
-
 
190
        while my_gt(val, max(pvalues[1:-1])):
-
 
191
            if my_gt(val, min(pvalues[1:-1])*10.0):
-
 
192
                val     = val     *  0.1;
-
 
193
                val_exp = val_exp * 10.0;
-
 
194
            else:
-
 
195
                break;
-
 
196
 
-
 
197
 
-
 
198
    # select nearest values
-
 
199
    for i in range(len(pvalues)-1):
-
 
200
        vdn = pvalues[i];
-
 
201
        vup = pvalues[i+1];
-
 
202
        if vdn<=val and val<=vup:
-
 
203
            break;
-
 
204
 
-
 
205
    vdn_exp = val_exp
-
 
206
    vup_exp = val_exp
-
 
207
 
-
 
208
    if vdn<pvalues[1]:
49
co=simplify(d2).collect(w)
209
        vdn *= 10.0
-
 
210
        vdn_exp *= 0.1
-
 
211
 
-
 
212
    if vup>pvalues[-2]:
-
 
213
        vup *= 0.1
-
 
214
        vup_exp *= 10.0
-
 
215
 
-
 
216
    return [ (vdn,vdn_exp), (vup,vup_exp) ];
-
 
217
 
-
 
218
def select_one_nearest(val,pvalues_name='e24'):
-
 
219
 
-
 
220
    lval = select_two_nearest(val,1.0,pvalues_name)
-
 
221
 
-
 
222
    (vdn,vdn_exp) = lval[0]
-
 
223
    (vup,vup_exp) = lval[1]
-
 
224
 
-
 
225
    vdn *= vdn_exp
-
 
226
    vup *= vup_exp
-
 
227
 
-
 
228
    if math.fabs( (vdn-val)/val ) <= math.fabs( (vup-val)/val ):
-
 
229
        return vdn
-
 
230
    else:
-
 
231
        return vup
-
 
232
 
-
 
233
def get_neighbour_value(val,dir='up',pvalues_name='e24'):
-
 
234
   
-
 
235
    pvalues = select_pvalues_list(pvalues_name)
-
 
236
    exp = 1.0
-
 
237
 
-
 
238
    found_v = None
-
 
239
    found_idx = None
-
 
240
    for idx,v in enumerate(pvalues[1:-1]):
-
 
241
        if math.isclose(val,v,rel_tol=1e-3):
-
 
242
            found_v = v
-
 
243
            found_idx = idx
-
 
244
 
-
 
245
            #print(' found {} {}'.format(found_v,found_idx))
-
 
246
            break
-
 
247
   
-
 
248
    if found_v is None:
-
 
249
        raise NameError('found_v is None!')
-
 
250
        sys.exit(1)
-
 
251
 
-
 
252
    if dir=='up':
-
 
253
        if math.isclose(found_v,pvalues[-2],rel_tol=1e-3):
-
 
254
            next_v = pvalues[1]
-
 
255
            exp = 10.0
-
 
256
        else:
-
 
257
            tmp = pvalues[1:-1]
-
 
258
            #print('  tmp {}'.format(tmp))
-
 
259
            next_v = tmp[found_idx+1]
-
 
260
       
-
 
261
    elif dir=='down':
-
 
262
        if math.isclose(found_v,pvalues[1],rel_tol=1e-3):
-
 
263
            next_v = pvalues[-2]
-
 
264
            exp = 0.1
-
 
265
        else:
-
 
266
            tmp = pvalues[1:-1]
-
 
267
            next_v = tmp[found_idx-1]
-
 
268
 
-
 
269
    else:
-
 
270
        raise NameError('dir is neither "up" nor "down"!')
-
 
271
        sys.exit(1)
-
 
272
 
-
 
273
    return (next_v,exp)
-
 
274
 
-
 
275
 
-
 
276
def val_exp_le( val1, val1_exp, val2, val2_exp ):
-
 
277
 
-
 
278
    return (val1_exp < val2_exp) or ( math.isclose(val1_exp, val2_exp, rel_tol=1e-3) and ( (val1 < val2) or math.isclose(val1, val2, rel_tol=1e-3) ) )
-
 
279
 
-
 
280
 
-
 
281
def select_values_in_range(vrange, vrange_exp, pvalues='e24'):
-
 
282
# range is [min,max]
-
 
283
# returns list of values already multiplied by exp
-
 
284
 
-
 
285
    vmin=vrange[0]
-
 
286
    vmax=vrange[1]
-
 
287
 
-
 
288
    if vmax<=vmin:
-
 
289
        raise NameError('wrong vrange: [0] must be bigger than [1]')
-
 
290
        sys.exit(1)
-
 
291
 
-
 
292
    # expand interval by nearest preferred values
-
 
293
    vmin_vals = select_two_nearest(vmin,vrange_exp, pvalues_name=pvalues)
-
 
294
    vmax_vals = select_two_nearest(vmax,vrange_exp, pvalues_name=pvalues)
-
 
295
    #print(vmin,vmax,vrange_exp)
-
 
296
    #print(vmin_vals,vmax_vals)
-
 
297
 
-
 
298
 
-
 
299
    # start building values list
-
 
300
 
-
 
301
    vmin_val_0, vmin_exp_0 = vmin_vals[0]
-
 
302
    vmin_val_1, vmin_exp_1 = vmin_vals[1]
-
 
303
    vmax_val_0, vmax_exp_0 = vmax_vals[0]
-
 
304
    vmax_val_1, vmax_exp_1 = vmax_vals[1]
-
 
305
 
-
 
306
    if math.isclose(vmin_val_1*vmin_exp_1, vmin*vrange_exp, rel_tol=1e-3):
-
 
307
        curr_v, curr_exp = vmin_vals[1]
-
 
308
    else:
-
 
309
        curr_v, curr_exp = vmin_vals[0]
-
 
310
 
-
 
311
    if math.isclose(vmax_val_0*vmax_exp_0, vmax*vrange_exp, rel_tol=1e-3):
-
 
312
        vmax_v, vmax_exp = vmax_vals[0]
-
 
313
    else:
-
 
314
        vmax_v, vmax_exp = vmax_vals[1]
-
 
315
 
-
 
316
    values_range = []
-
 
317
 
-
 
318
    #print('vmaxs: {} {}'.format(vmax_v, vmax_exp))
-
 
319
    while val_exp_le( curr_v, curr_exp, vmax_v, vmax_exp ):
-
 
320
     
-
 
321
        #print('currs: {} {}'.format(curr_v, curr_exp))
-
 
322
 
-
 
323
        values_range = values_range + [ (curr_v, curr_exp) ]
-
 
324
 
-
 
325
        next_v, exp_update = get_neighbour_value( curr_v, dir='up', pvalues_name=pvalues )
-
 
326
       
-
 
327
        #print('nexts: {} {}\n'.format(next_v, exp_update))
-
 
328
 
-
 
329
        curr_v = next_v
-
 
330
        curr_exp *= exp_update
-
 
331
 
-
 
332
   
-
 
333
    return values_range
-
 
334
 
-
 
335
 
-
 
336
 
-
 
337
def calc_mfb2_parameters(r1,r2,r3,c1,c2):
-
 
338
 
-
 
339
    wc = 1.0/math.sqrt(c1*c2*r2*r3)
-
 
340
    k  = (-r2)/r1
-
 
341
    q  = 1.0 / (wc * c1 * ((1.0-k)*r3 + r2))
-
 
342
 
-
 
343
    return (wc,k,q)
-
 
344
 
-
 
345
 
-
 
346
def randomize_mfb2(r1,r2,r3,c1,c2, c_precision=0.05, r_precision=0.01, iters=1000):
-
 
347
 
-
 
348
    (wc0, k0, q0) = calc_mfb2_parameters(r1,r2,r3,c1,c2)
-
 
349
 
-
 
350
    d_wc = 0.0
-
 
351
    d_k  = 0.0
-
 
352
    d_q  = 0.0
-
 
353
 
-
 
354
    for i in range(iters):
-
 
355
        dr1 = random.uniform(1.0-r_precision,1.0+r_precision)
-
 
356
        dr2 = random.uniform(1.0-r_precision,1.0+r_precision)
-
 
357
        dr3 = random.uniform(1.0-r_precision,1.0+r_precision)
-
 
358
 
-
 
359
        dc1 = random.uniform(1.0-c_precision,1.0+c_precision)
-
 
360
        dc2 = random.uniform(1.0-c_precision,1.0+c_precision)
-
 
361
 
-
 
362
        rr1 = r1 * dr1
-
 
363
        rr2 = r2 * dr2
-
 
364
        rr3 = r3 * dr3
-
 
365
 
-
 
366
        rc1 = c1 * dc1
-
 
367
        rc2 = c2 * dc2
-
 
368
 
-
 
369
        (wc,k,q) = calc_mfb2_parameters(rr1,rr2,rr3,rc1,rc2)
-
 
370
 
-
 
371
        d_wc = max(d_wc, abs(wc-wc0))
-
 
372
        d_k  = max(d_k,  abs(k-k0)  )
-
 
373
        d_q  = max(d_q,  abs(q-q0)  )
-
 
374
 
-
 
375
    return (d_wc/wc0, d_k/k0, d_q/q0)
-
 
376
 
-
 
377
 
-
 
378
 
-
 
379
def calc_filter( wc_set=2*math.pi*30000, q_set=1.0, k_set=(-1.17), r1_range=[20.0,30.0], r1_exp=1e3, r1_div=3.0, r1_add=0.0, r_pvalues='e24', c1_range=[33.0,4700.0], c1_exp=1e-12, c_pvalues='e12'):
-
 
380
 
-
 
381
    c1_values = select_values_in_range( c1_range, c1_exp, pvalues=c_pvalues )
-
 
382
 
-
 
383
    r1x3_values = select_values_in_range( [x for x in r1_range], r1_exp, pvalues=r_pvalues )
-
 
384
    print(r1_range,r1_exp,r1x3_values)
-
 
385
    r1_values = [(x/r1_div+r1_add/y,y) for (x,y) in r1x3_values]
-
 
386
 
-
 
387
    print( 'c1 values for sweep: {}'.format([x*y for (x,y) in c1_values]) )
-
 
388
    print( 'r1 values for sweep: {}'.format([x*y for (x,y) in r1_values]) )
-
 
389
 
-
 
390
    print( '\ncalculating filter for: q={}, k={}, fc={}'.format(q_set,k_set,wc_set/(2*math.pi)) )
-
 
391
 
-
 
392
 
-
 
393
    f_values=[]
-
 
394
 
-
 
395
    for r1 in [x*y for (x,y) in r1_values]:
-
 
396
        for c1 in [x*y for (x,y) in c1_values]:
-
 
397
 
-
 
398
            r2_ideal = (-1) * k_set * r1
-
 
399
 
-
 
400
            c2_ideal = (q_set * (k_set - 1.0)) / (r2_ideal * wc_set * (c1 * q_set * r2_ideal * wc_set - 1.0))
-
 
401
 
-
 
402
           
-
 
403
            r3_ideal = (c1 * q_set * r2_ideal * wc_set - 1.0) / ( (k_set - 1.0) * q_set * wc_set * c1 )
-
 
404
 
-
 
405
            if r2_ideal<=0.0 or c2_ideal<=0.0 or r3_ideal<=0.0:
-
 
406
                continue
-
 
407
 
-
 
408
            print('\ntry c1={:1.1e}, r1={:.1f}:'.format(c1,r1))
-
 
409
            print(' ideal values: r2={:.1f}, r3={:.1f}, c2={:1.4e}'.format(r2_ideal, r3_ideal, c2_ideal))
-
 
410
 
-
 
411
            r2_real = select_one_nearest(r2_ideal, r_pvalues)
-
 
412
            c2_real = select_one_nearest(c2_ideal, c_pvalues)
-
 
413
            r3_real = select_one_nearest(r3_ideal, r_pvalues)
-
 
414
            print(' nearest values: r2={:.1f}, r3={:.1f}, c2={:1.1e}'.format(r2_real, r3_real, c2_real))
-
 
415
 
-
 
416
            #wc_real = 1.0/math.sqrt(c1*c2_real*r2_real*r3_real)
-
 
417
            #k_real = (-r2_real)/r1
-
 
418
            #q_real = 1.0 / (wc_real * c1 * ((1.0-k_real)*r3_real + r2_real))
-
 
419
            (wc_real,k_real,q_real) = calc_mfb2_parameters(r1,r2_real,r3_real,c1,c2_real)
-
 
420
 
-
 
421
            print(' real parameters: q={:.4f}, k={:.4f}, fc={:.1f}'.format(q_real,k_real,wc_real/(2*math.pi)) )
-
 
422
 
-
 
423
            #f_values += [ (r1,r2_real,r3_real, c1, c2_real, wc_real, k_real, q_real) ]
-
 
424
            f_values += [ {'r1':r1,'r2':r2_real,'r3':r3_real, 'c1':c1, 'c2':c2_real, 'wc':wc_real, 'k':k_real, 'q':q_real} ]
-
 
425
 
-
 
426
 
-
 
427
   
-
 
428
    print(f_values)
-
 
429
 
-
 
430
    # sort values by cutoff freq match
-
 
431
    print('\n\n\n sorted by cutoff freq:')
-
 
432
    for e in  sorted(f_values, key = lambda tup: abs((tup['wc']-wc_set)/wc_set) ):
-
 
433
        print('  c1={:1.1e}, r1={:.1f}, r2={:.1f}, r3={:.1f}, c2={:1.1e}, q={:.4f}, k={:.4f}, fc={:.1f}'.format(e['c1'],e['r1'],e['r2'],e['r3'],e['c2'],e['q'],e['k'],e['wc']/(2*math.pi)) )
-
 
434
        (p_wc, p_k, p_q) = randomize_mfb2(e['r1'],e['r2'],e['r3'],e['c1'],e['c2'])
-
 
435
        print('   percent_fc={:.2f}%, percent_k={:.2f}%, percent_q={:.2f}%'.format(100*p_wc,100*p_k,100*p_q))
-
 
436
 
-
 
437
    # sort values by q match
-
 
438
    print('\n\n\n sorted by q:')
-
 
439
    for e in  sorted(f_values, key = lambda tup: abs((tup['q']-q_set)/q_set) ):
-
 
440
        print('  c1={:1.1e}, r1={:.1f}, r2={:.1f}, r3={:.1f}, c2={:1.1e}, q={:.4f}, k={:.4f}, fc={:.1f}'.format(e['c1'],e['r1'],e['r2'],e['r3'],e['c2'],e['q'],e['k'],e['wc']/(2*math.pi)) )
-
 
441
 
-
 
442
 
-
 
443
 
-
 
444
def main():
-
 
445
 
-
 
446
    calc_mfb3_lowpass()
-
 
447
 
-
 
448
    #calc_filter()
-
 
449
 
-
 
450
    #print(" #### AY ####")
-
 
451
    #calc_filter( wc_set=2*math.pi*30000, q_set=1.0, k_set=(-1.75), r1_range=[20.0,30.0], r1_exp=1e3, r1_div=3.0, r_pvalues='e24', c1_range=[33.0,4700.0], c1_exp=1e-12, c_pvalues='e12')
-
 
452
 
50
 
453
#    print(" #### beep ####")
51
print(co)
454
#    calc_filter( wc_set=2*math.pi*30000, q_set=1.0, k_set=(-0.388), r1_range=[4.7,10.0], r1_exp=1e3, r1_div=1.0, r1_add=750, r_pvalues='e24', c1_range=[33.0,4700.0], c1_exp=1e-12, c_pvalues='e12')
-
 
455
 
52
 
456
 
53
 
457
if __name__=="__main__":
54
w1,w2,q=symbols('w1,w2,q')
458
    main()
-
 
459
 
55
 
-
 
56
#w1 - 1st order, w2,q - 2nd order
-
 
57
hd=(1+I*w/w1)*(1+I*w/(w2*q)-w**2/w2**2)
460
 
58
 
-
 
59
hdo = collect(expand(hd),w)
461
 
60
 
-
 
61
print('w**3: {}'.format(hdo.coeff(w,3)))
-
 
62
print('w**2: {}'.format(hdo.coeff(w,2)))
-
 
63
print('w**1: {}'.format(hdo.coeff(w,1)))
-
 
64
print('w**0: {}'.format(hdo.coeff(w,0)))