**NOTE**: Further updates to this code will be posted on GitHub.

This builds on the last example by using the
`simulate`

function of a `Circuit`

to drive a circuit simulator
(Ahkab) with a `Population`

of random `Circuit`

s made of random
`Component`

s (`Resistor`

, `Inductor`

. and `Capacitor`

) representing low-pass filters. It runs an
AC analysis and minimizes the maximum attenuation in the pass band and maximizes the minimum
attenuation in the stop band. If `pre_seed`

is altered to `pre_seed = True`

, the population will
be seeded with two pre-existing circuits found during earlier runs.

The `score`

code in `Circuit`

is largely derived from
this example. A `Population`

holds
`population_size`

`Circuit`

s. When the `simulate`

generator of a `Population`

is iterated over,
the `score`

and `simulate`

methods of each `Circuit`

in the `Population`

are called. Circuits that
fail to simulate correctly are removed from the scoring before being returned.

In each generation:

- the best
`top_n`

are copied unmutated, - the top 3 are copied
`top_n`

times and mutated, - the
`top_n`

are copied and mutated, - the top 3 are copied
`top_n`

times and recombined, - the
`top_n`

are copied and recombined, - and the rest are regenerated randomly.

`mutate`

has a random chance of `mutate_add`

, `mutate_delete`

, `mutate_value`

, `mutate_node`

, or
no effect. Recombination selects randomly from the pool of potential circuits and selects random
components from the two circuits to form a new circuit of the average size of the parent circuits.
All circuits being `recombine`

d are done in a single pass. If no viable scores exist in a
generation, the population is `repopulate`

d.

**Note**: This expects a folder (`ramdisk`

) within the current directory. Ahkab uses this as a
scratch pad for simulation results. Ahkab's `cvslib`

expects a string for `filename`

, so passing
a `tempfile.SpooledTemporaryFile`

isn't possible. You should consider mounting a ramdisk at
`ramdisk`

for increased speed and reduced wear on your drive. For example:

`$ mkdir ramdisk $ sudo mount -t tmpfs none ramdisk`

If you want to see the raw results of Ahkab's analysis, you can `cat ramdisk/sim.ac`

, or for
near-realtime viewing, you can `watch -n0.1 cat ramdisk/sim.ac`

. You can set `debug = True`

to
increase the simulation verbosity and include mutation and recombination details.

This is tested on Python 2.7.6 with Ahkab fbd9777e7a, SciPy 0.12.1, NumPy 1.7.1, and SymPy 0.7.2.

**Usage**: `./filter.py`

**Sample Output**:

`[(60.202476256287355, [<__main__.Resistor object at 0x3925e90> R3 0 n4 100000, <__main__.Resistor object at 0x3925ed0> R4 n5 0 300, <__main__.Resistor object at 0x3925450> R5 n2 n3 330, <__main__.Resistor object at 0x3925f90> R6 n8 n6 160, <__main__.Inductor object at 0x39256d0> L0 n8 n5 6.2e-08, <__main__.Inductor object at 0x3925690> L1 n4 n6 3.3e-07, <__main__.Inductor object at 0x3929c90> L2 n1 n3 1.3e-08, <__main__.Capacitor object at 0x3929fd0> C1 n2 n7 8.2e-08, <__main__.Capacitor object at 0x3929ed0> C2 n7 n5 6.8e-06, <__main__.Capacitor object at 0x3929e10> C3 n6 0 3.9e-07]), ... Top Score (generation 55): 60.2024762563 * TITLE: Untitled R3 0 n4 100000 R4 n5 0 300 R5 n2 n3 330 R6 n8 n6 160 L0 n8 n5 6.2e-08 L1 n4 n6 3.3e-07 L2 n1 n3 1.3e-08 C1 n2 n7 8.2e-08 C2 n7 n5 6.8e-06 C3 n6 0 3.9e-07 V1 n1 0 type=vdc vdc=5 vac=1 arg=0 type=pulse v1=0 v2=1 td=5e-07 per=2 tr=1e-12 tf=1e-12 pw=1 (models and analysis directives are omitted) log((MASB / MAPB), 10) = 4.961829 Maximum attenuation in the pass band (0-2000 Hz) is 3.33976e-05 dB Minimum attenuation in the stop band (6500 Hz - Inf) is 3.05875 dB`

**filter.py**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444

#!/usr/bin/env python
import random
import ahkab
from ahkab import circuit, printing, devices
import scipy
import scipy.interpolate
import numpy
import math
import time
import copy
from pprint import pprint as pp
debug = False
class Component(object):
def __init__(self, value=None, part_id=None, ext_n1=None, ext_n2=None):
self.value = value
self.part_id = part_id
self.ext_n1 = ext_n1
self.ext_n2 = ext_n2
def __repr__(self):
return '<%s.%s object at %s> %s %s %s %s' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self)),
self.part_id,
self.ext_n1,
self.ext_n2,
self.value)
class Resistor(Component):
common = [ # In ohms
10, 11, 12, 13, 15, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 43, 47, 51, 56, 62, 68, 75, 82,
91, 100, 110, 120, 130, 150, 160, 180, 200, 220, 240, 270, 300, 330, 360, 390, 430, 470,
510, 560, 620, 680, 750, 820, 910, 1000, 1100, 1200, 1300, 1500, 1600, 1800, 2000, 2200,
2400, 2700, 3000, 3300, 3600, 3900, 4300, 4700, 5100, 5600, 6200, 6800, 7500, 8200, 9100,
10000, 11000, 12000, 13000, 15000, 16000, 18000, 20000, 22000, 24000, 27000, 30000, 33000,
36000, 39000, 43000, 47000, 51000, 56000, 62000, 68000, 75000, 82000, 91000, 100000,
110000, 120000, 130000, 150000, 160000, 180000, 200000, 220000, 240000, 270000, 300000,
330000, 360000, 390000, 430000, 470000, 510000, 560000, 620000, 680000, 750000, 820000,
910000, 1000000, 1100000, 1200000, 1300000, 1500000, 1600000, 1800000, 2000000, 2200000,
2400000, 2700000, 3000000, 3300000, 3600000, 3900000, 4300000, 4700000, 5100000, 5600000,
6200000, 6800000, 7500000, 8200000, 9100000, 10000000, 11000000, 12000000, 13000000,
15000000, 16000000, 18000000, 20000000, 22000000, 24000000, 27000000, 30000000, 33000000,
36000000, 39000000, 43000000, 47000000, 51000000, 56000000, 62000000, 68000000, 75000000,
82000000, 91000000]
class Inductor(Component):
common = [ # In henries
1e-09, 1e-08, 1e-07, 1e-06, 1e-05, 1e-09, 1.1e-08, 1.1e-07, 1.1e-06, 1.1e-05, 1e-09,
1.2e-08, 1.2e-07, 1.2e-06, 1.2e-05, 1e-09, 1.3e-08, 1.3e-07, 1.3e-06, 1.3e-05, 2e-09,
1.5e-08, 1.5e-07, 1.5e-06, 1.5e-05, 2e-09, 1.6e-08, 1.6e-07, 1.6e-06, 1.6e-05, 2e-09,
1.8e-08, 1.8e-07, 1.8e-06, 1.8e-05, 2e-09, 2e-08, 2e-07, 2e-06, 2e-05, 2e-09, 2.2e-08,
2.2e-07, 2.2e-06, 2.2e-05, 2e-09, 2.4e-08, 2.4e-07, 2.4e-06, 2.4e-05, 3e-09, 2.7e-08,
2.7e-07, 2.7e-06, 2.7e-05, 3e-09, 3e-08, 3e-07, 3e-06, 3e-05, 3e-09, 3.3e-08, 3.3e-07,
3.3e-06, 3.3e-05, 4e-09, 3.6e-08, 3.6e-07, 3.6e-06, 3.6e-05, 4e-09, 3.9e-08, 3.9e-07,
3.9e-06, 3.9e-05, 4e-09, 4.3e-08, 4.3e-07, 4.3e-06, 4.3e-05, 5e-09, 4.7e-08, 4.7e-07,
4.7e-06, 4.7e-05, 5e-09, 5.1e-08, 5.1e-07, 5.1e-06, 5.1e-05, 6e-09, 5.6e-08, 5.6e-07,
5.6e-06, 5.6e-05, 6e-09, 6.2e-08, 6.2e-07, 6.2e-06, 6.2e-05, 7e-09, 6.8e-08, 6.8e-07,
6.8e-06, 6.8e-05, 8e-09, 7.5e-08, 7.5e-07, 7.5e-06, 7.5e-05, 8e-09, 8.2e-08, 8.2e-07,
8.2e-06, 8.2e-05, 9e-09, 8.7e-08, 8.7e-07, 8.7e-06, 8.7e-05, 9e-09, 9.1e-08, 9.1e-07,
9.1e-06, 9.1e-05]
class Capacitor(Component):
common = [ # In farads
1e-11, 1e-10, 1e-09, 1e-08, 1e-07, 1e-06, 1.2e-11, 1.2e-10, 1.2e-09, 1.2e-08, 1.2e-07,
1.2e-06, 1.5e-11, 1.5e-10, 1.5e-09, 1.5e-08, 1.5e-07, 1.5e-06, 1.8e-11, 1.8e-10, 1.8e-09,
1.8e-08, 1.8e-07, 1.8e-06, 2.2e-11, 2.2e-10, 2.2e-09, 2.2e-08, 2.2e-07, 2.2e-06, 2.7e-11,
2.7e-10, 2.7e-09, 2.7e-08, 2.7e-07, 2.7e-06, 3.3e-11, 3.3e-10, 3.3e-09, 3.3e-08, 3.3e-07,
3.3e-06, 3.9e-11, 3.9e-10, 3.9e-09, 3.9e-08, 3.9e-07, 3.9e-06, 4.7e-11, 4.7e-10, 4.7e-09,
4.7e-08, 4.7e-07, 4.7e-06, 5.6e-11, 5.6e-10, 5.6e-09, 5.6e-08, 5.6e-07, 5.6e-06, 6.8e-11,
6.8e-10, 6.8e-09, 6.8e-08, 6.8e-07, 6.8e-06, 8.2e-11, 8.2e-10, 8.2e-09, 8.2e-08, 8.2e-07,
8.2e-06]
class Circuit(list):
def __init__(self, title="Untitled", num_nodes=0, outfile='ramdisk/sim.ac', weights=None, random=None):
self.title = title # Title of the circuit
self.num_nodes = num_nodes # Number of connection nodes
self.outfile = outfile # The filename for Ahkab's scratchpad
self.weights = weights if weights else [
10.0, # log 10 (Minimum attenuation in the stop band / Maximum attenuation in the pass band)
-100.0, # Maximum attenuation in the pass band
10.0, # Minimum attenuation in the stop band
-2.0, # Number of nodes
-2.0 # Number of parts
]
self.circuit = None # An Ahkab circuit object
self.max_attenuation_pass_band = None # Tuple of (pass band upper frequency, maximum attenuation)
self.min_attenuation_stop_band = None # Tuple of (stop band lower frequency, minimum attenuation)
# Table of `Component` types to lists of [subclass, init method for Ahkab, subclass count]
self.component_types = {
'R': [Resistor, 'add_resistor', 0],
'L': [Inductor, 'add_inductor', 0],
'C': [Capacitor, 'add_capacitor', 0]
}
# Populate the `Circuit` with random `Component`s
if random: self.random()
# Creates many random `Component`s
def random(self):
self.num_nodes = random.randint(3, 8)
for i in range(0, random.randint(4, 20)):
# Make sure to append to self (a `Circuit`) instead of overwriting with a basic `list`
self.append(self.random_part())
# Creates a random `Component`
def random_part(self):
# Create a list of all the nodes to select from, emphasizing ground
all_nodes = (['0'] * 3) + ["n%d" % i for i in range(1, self.num_nodes)]
a_type = random.choice(self.component_types.keys())
a_class, an_init, an_id = self.component_types[a_type]
a_part = a_class()
a_part.value = random.choice(a_part.common)
a_part.part_id = "%s%d" % (a_type, an_id)
a_part.ext_n1 = random.choice(all_nodes)
a_part.ext_n2 = random.choice(all_nodes)
# Increment per-subclass counter (for next `an_id`)
self.component_types[a_type][2] += 1
return a_part
# Mutations to fine-tune the `top_n` solutions
def mutate(self):
mutation = random.randint(0, 1000)
if debug:
print "Mutating (from):"
pp(self)
if mutation < 400: self.mutate_delete()
elif mutation < 500: self.mutate_add()
elif mutation < 800: self.mutate_value()
elif mutation < 900: self.mutate_node()
if debug:
print "Mutating (to):"
pp(self)
print "\n"
# Deletes a `Component`
def mutate_delete(self):
if debug:
print "Mutate 'delete'"
size = len(self)
if size > 1:
del self[random.randint(0, size-1)]
# Adds a `Component`
def mutate_add(self):
if debug:
print "Mutate 'add'"
self.append(self.random_part())
# Selects a new `value` for a random `Component`
def mutate_value(self):
if debug:
print "Mutate 'value'"
a_part = self[random.randint(0, len(self)-1)]
a_part.value = random.choice(a_part.common)
def mutate_node(self):
if debug:
print "Mutate 'node'"
# Create a list of all the nodes to select from, emphasizing ground
all_nodes = (['0'] * 3) + ["n%d" % i for i in range(1, self.num_nodes)]
# Choose a random `Component`
a_part = self[random.randint(0, len(self)-1)]
# Choose a random connection node to swap
if random.randint(0, 1):
a_part.ext_n1 = random.choice(all_nodes)
else:
a_part.ext_n2 = random.choice(all_nodes)
# Drive the Ahkab circuit simulator
def simulate(self):
# Build a copy of the circuit for Ahkab
self.circuit = circuit.circuit(title=self.title)
# Create nodes
for i in range(0, self.num_nodes):
self.circuit.create_node("n%d" % i)
# Create passive components
for i in self:
# Call the init method of the current component type
getattr(self.circuit, self.component_types[i.part_id[0]][1])(
i.part_id,
i.ext_n1,
i.ext_n2,
**{i.part_id[0]: i.value}) # Create 'R', 'L', or 'C' kwarg for `self.circuit.add_*`
# Add a voltage source
voltage_step = devices.pulse(v1=0, v2=1, td=500e-9, tr=1e-12, pw=1, tf=1e-12, per=2)
self.circuit.add_vsource(name="V1", ext_n1='n1', ext_n2='0', vdc=5, vac=1, function=voltage_step)
# Simulate the circuit with an AC analysis
return ahkab.ac.ac_analysis(self.circuit, 1e3, 100, 1e5, 'LOG', outfile=self.outfile, verbose=0)
def score(self):
r = self.simulate()
print "\n"
# Didn't simulate
if not r: return None
try:
# Normalize the output to the low frequency value and convert to array
norm_out = numpy.asarray(r['|Vn4|'].T/r['|Vn4|'].max())
# Convert to dB
norm_out_db = 20 * numpy.log10(norm_out)
# Reshape to be scipy-friendly
norm_out_db = norm_out_db.reshape((max(norm_out_db.shape),))
# Convert angular frequencies to Hz and convert matrix to array
frequencies = numpy.asarray(r['w'].T/2/math.pi)
# Reshape to be scipy-friendly
frequencies = frequencies.reshape((max(frequencies.shape),))
# call scipy to interpolate
norm_out_db_interpolated = scipy.interpolate.interp1d(frequencies, norm_out_db)
self.max_attenuation_pass_band = (2e3, -1.0*norm_out_db_interpolated(2e3))
self.min_attenuation_stop_band = (6.5e3, -1.0*norm_out_db_interpolated(6.5e3))
# If ANYTHING goes wrong, we just mark the circuit as bad. Lazy. (Possibly bad. Probably bad.)
except: return None
# Eliminate unusable results
if (self.max_attenuation_pass_band[1] == -0) or math.isnan(self.max_attenuation_pass_band[1]):
return None
if (self.min_attenuation_stop_band[1] == -0) or math.isnan(self.min_attenuation_stop_band[1]):
return None
if debug:
printing.print_circuit(self.circuit)
print "log((MASB / MAPB), 10) = %f" % math.log((self.min_attenuation_stop_band[1] / self.max_attenuation_pass_band[1]), 10)
print "Maximum attenuation in the pass band (0-%g Hz) is %g dB" % self.max_attenuation_pass_band
print "Minimum attenuation in the stop band (%g Hz - Inf) is %g dB\n" % self.min_attenuation_stop_band
# Form a draft of the final score
a_score = [
math.log((self.min_attenuation_stop_band[1] / self.max_attenuation_pass_band[1]), 10),
self.max_attenuation_pass_band[1],
self.min_attenuation_stop_band[1],
self.num_nodes,
len(self)
]
# Weight the draft version of the final score
return sum([a_weight * a_score for (a_weight, a_score) in zip(self.weights, a_score)])
class Population(list):
def __init__(self, population=None, population_size=200, top_n=5, generation=0):
self.population_size = population_size
self.top_n = top_n
self.generation = generation
self.repopulate(population=population, population_size=self.population_size)
def repopulate(self, population=None, population_size=None):
if population_size: self.population_size = population_size
# Make sure to append to self (a `Population`) instead of overwriting with a basic `list`
del self[:]
if population:
self += population
else:
self += [Circuit(random=True) for i in range(0, self.population_size)]
def recombine(self, a, b):
a_circuit = Circuit()
# Create a circuit with the mean number of components of `a` and `b`, choosing
# components randomly from either `a` or `b`. Renumber the components to avoid overlaps.
for i in range(0, ((len(a) + len(b)) / 2)):
a_part = copy.deepcopy(random.choice(random.choice([a, b])))
a_part.part_id = "%s%d" % (a_part.part_id[0], a_circuit.component_types[a_part.part_id[0]][2])
a_circuit.append(a_part)
a_circuit.component_types[a_part.part_id[0]][2] += 1
return a_circuit
def simulate(self):
while True:
scores = []
# Simulate and score each member of the population
for a_member in self:
a_score = a_member.score()
if a_score: scores.append((a_score, a_member))
# Sort the results
scores.sort(key=lambda x: -x[0])
# No surviving circuits in this generation
if not scores:
self.repopulate()
print "Generation %d: mulligan" % self.generation
self.generation += 1
# Pause for humans to read post-generation results (Optional)
time.sleep(1)
continue
# Return a tuple of (last simulated generation, [(score, circuit)...])
yield (self.generation, scores)
self.generation += 1
# Pristine copies of the `top_n`
new_population = [copy.deepcopy(a_score[1]) for a_score in scores[:self.top_n]]
# Mutated copies of the `top_n`
mutated_population = (copy.deepcopy([scores[0][1]]) * self.top_n) + \
(copy.deepcopy([scores[1][1]]) * self.top_n) + \
(copy.deepcopy([scores[2][1]]) * self.top_n) + \
[copy.deepcopy(a_score[1]) for a_score in scores[:self.top_n]]
for a_member in mutated_population:
a_member.mutate()
new_population += mutated_population
# Recombined copies of the `top_n`
recombined_population = (copy.deepcopy([scores[0][1]]) * self.top_n) + \
(copy.deepcopy([scores[1][1]]) * self.top_n) + \
(copy.deepcopy([scores[2][1]]) * self.top_n) + \
[copy.deepcopy(a_score[1]) for a_score in scores[:self.top_n]]
for i in range(0, len(recombined_population) * 2):
a_member = random.choice(recombined_population)
b_member = random.choice(recombined_population)
new_member = self.recombine(a_member, b_member)
if debug:
print "\nCircuit A\n---------"
pp(a_member)
print "\nCircuit B\n---------"
pp(b_member)
print "\nNew Circuit\n---------"
pp(new_member)
print
new_population.append(new_member)
# Random new population
new_population += [Circuit(random=True) for i in range(0, self.population_size - len(new_population))]
# Make sure to append to self (a `Population`) instead of overwriting with a basic `list`
del self[:]
self += new_population
if __name__ == "__main__":
desired_score = 100
top_score = None
a_population = Population()
pre_seed = False
if pre_seed:
# Create a seed circuit (discovered by this GA and saved)
a_circuit = Circuit()
a_circuit.component_types['R'][2] = 7
a_circuit.component_types['L'][2] = 4
a_circuit.component_types['C'][2] = 4
a_circuit += [
Resistor( part_id='R0', ext_n1='0', ext_n2='n8', value=130000),
Resistor( part_id='R1', ext_n1='n3', ext_n2='n1', value=510),
Resistor( part_id='R2', ext_n1='0', ext_n2='n1', value=100000),
Resistor( part_id='R3', ext_n1='0', ext_n2='n4', value=100000),
Resistor( part_id='R4', ext_n1='n5', ext_n2='0', value=300),
Resistor( part_id='R5', ext_n1='n2', ext_n2='n3', value=330),
Resistor( part_id='R6', ext_n1='n8', ext_n2='n6', value=160),
Inductor( part_id='L0', ext_n1='n8', ext_n2='n5', value=6.2e-08),
Inductor( part_id='L1', ext_n1='n4', ext_n2='n6', value=3.3e-07),
Inductor( part_id='L2', ext_n1='n1', ext_n2='n3', value=1.3e-08),
Inductor( part_id='L3', ext_n1='0', ext_n2='0', value=1.3e-07),
Capacitor( part_id='C0', ext_n1='0', ext_n2='n4', value=5.6e-09),
Capacitor( part_id='C1', ext_n1='n2', ext_n2='n7', value=8.2e-08),
Capacitor( part_id='C2', ext_n1='n7', ext_n2='n5', value=6.8e-06),
Capacitor( part_id='C3', ext_n1='n6', ext_n2='0', value=3.9e-07)
]
# Append the seed circuit to the population
a_population.append(a_circuit)
a_population.population_size += 1
# Create a second seed circuit
a_circuit = Circuit()
a_circuit.component_types['R'][2] = 4
a_circuit.component_types['L'][2] = 3
a_circuit.component_types['C'][2] = 3
a_circuit += [
Resistor( part_id='R0', ext_n1='0', ext_n2='n4', value=100000),
Resistor( part_id='R1', ext_n1='n5', ext_n2='0', value=300),
Resistor( part_id='R2', ext_n1='n2', ext_n2='n3', value=330),
Resistor( part_id='R3', ext_n1='n8', ext_n2='n6', value=160),
Inductor( part_id='L0', ext_n1='n8', ext_n2='n5', value=6.2e-08),
Inductor( part_id='L1', ext_n1='n4', ext_n2='n6', value=3.3e-07),
Inductor( part_id='L2', ext_n1='n1', ext_n2='n3', value=1.3e-08),
Capacitor( part_id='C0', ext_n1='n2', ext_n2='n7', value=8.2e-08),
Capacitor( part_id='C1', ext_n1='n7', ext_n2='n5', value=6.8e-06),
Capacitor( part_id='C2', ext_n1='n6', ext_n2='0', value=3.9e-07)
]
# Append the seed circuit to the population
a_population.append(a_circuit)
a_population.population_size += 1
for (generation, scores) in a_population.simulate() :
# Print out the remaining circuits
print "\n\n"
top_score = scores[0]
print "Scores\n------\n"
pp(scores)
print "\n"
# Print the top score
print "Top Score (generation %d): %s\n\n" % (generation, top_score[0])
printing.print_circuit(top_score[1].circuit)
print "log((MASB / MAPB), 10) = %f" % math.log((top_score[1].min_attenuation_stop_band[1] / top_score[1].max_attenuation_pass_band[1]), 10)
print "Maximum attenuation in the pass band (0-%g Hz) is %g dB" % top_score[1].max_attenuation_pass_band
print "Minimum attenuation in the stop band (%g Hz - Inf) is %g dB" % top_score[1].min_attenuation_stop_band
# Good Enough answer found
if top_score[0] > desired_score:
break
# Pause for humans to read post-generation results (Optional)
time.sleep(2)