ZLayout EDA Library v1.0.0
Advanced Electronic Design Automation Layout Library with Bilingual Documentation
Loading...
Searching...
No Matches
eda_circuit_example.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""
3Advanced EDA Circuit Layout Example
4
5This example simulates a more realistic electronic circuit layout with:
6- Various component types (chips, resistors, capacitors, traces)
7- Different geometric constraints
8- Comprehensive analysis for manufacturing feasibility
9"""
10
11import sys
12import os
13import math
14
15# Add parent directory to path
16sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
17
18import zlayout
19import matplotlib.pyplot as plt
20
21
22class CircuitComponent:
23 """Represents a circuit component with properties."""
24
25 def __init__(self, name: str, geometry, component_type: str = "generic"):
26 self.name = name
27 self.geometry = geometry
28 self.component_type = component_type
29 self.pins = [] # List of pin locations
30
31 def add_pin(self, point: zlayout.Point, pin_name: str = ""):
32 """Add a pin to the component."""
33 self.pins.append((point, pin_name))
34
35
36def create_microcontroller(x: float, y: float) -> CircuitComponent:
37 """Create a microcontroller component."""
38 # Main body (rectangle)
39 body = zlayout.Rectangle(x, y, 15, 15)
40
41 # Convert to polygon for more complex analysis
42 geometry = body.to_polygon()
43
44 mcu = CircuitComponent("MCU_1", geometry, "microcontroller")
45
46 # Add pins around the perimeter
47 pin_spacing = 1.0
48 # Bottom pins
49 for i in range(8):
50 pin_x = x + 2 + i * pin_spacing
51 mcu.add_pin(zlayout.Point(pin_x, y), f"P{i}")
52
53 # Top pins
54 for i in range(8):
55 pin_x = x + 2 + i * pin_spacing
56 mcu.add_pin(zlayout.Point(pin_x, y + 15), f"P{i+8}")
57
58 return mcu
59
60
61def create_resistor(x: float, y: float, rotation: float = 0) -> CircuitComponent:
62 """Create a resistor component."""
63 # Basic resistor shape
64 length, width = 6, 2
65
66 # Create resistor body
67 vertices = [
68 zlayout.Point(-length/2, -width/2),
69 zlayout.Point(length/2, -width/2),
70 zlayout.Point(length/2, width/2),
71 zlayout.Point(-length/2, width/2)
72 ]
73
74 # Apply rotation and translation
75 cos_r, sin_r = math.cos(rotation), math.sin(rotation)
76 rotated_vertices = []
77 for v in vertices:
78 new_x = v.x * cos_r - v.y * sin_r + x
79 new_y = v.x * sin_r + v.y * cos_r + y
80 rotated_vertices.append(zlayout.Point(new_x, new_y))
81
82 geometry = zlayout.Polygon(rotated_vertices)
83 resistor = CircuitComponent("R1", geometry, "resistor")
84
85 # Add connection points
86 resistor.add_pin(zlayout.Point(x - length/2, y), "1")
87 resistor.add_pin(zlayout.Point(x + length/2, y), "2")
88
89 return resistor
90
91
92def create_capacitor(x: float, y: float) -> CircuitComponent:
93 """Create a capacitor component."""
94 # Capacitor body (smaller rectangle)
95 geometry = zlayout.Rectangle(x-2, y-1.5, 4, 3).to_polygon()
96
97 cap = CircuitComponent("C1", geometry, "capacitor")
98 cap.add_pin(zlayout.Point(x-2, y), "1")
99 cap.add_pin(zlayout.Point(x+2, y), "2")
100
101 return cap
102
103
104def create_trace(start: zlayout.Point, end: zlayout.Point, width: float = 0.3) -> CircuitComponent:
105 """Create a PCB trace (connection line with width)."""
106 # Calculate perpendicular vector for width
107 dx = end.x - start.x
108 dy = end.y - start.y
109 length = math.sqrt(dx*dx + dy*dy)
110
111 if length < 1e-10:
112 # Degenerate trace
113 geometry = zlayout.Rectangle(start.x, start.y, 0.1, 0.1).to_polygon()
114 else:
115 # Normalized perpendicular vector
116 perp_x = -dy * width / (2 * length)
117 perp_y = dx * width / (2 * length)
118
119 # Create trace as a polygon
120 vertices = [
121 zlayout.Point(start.x + perp_x, start.y + perp_y),
122 zlayout.Point(end.x + perp_x, end.y + perp_y),
123 zlayout.Point(end.x - perp_x, end.y - perp_y),
124 zlayout.Point(start.x - perp_x, start.y - perp_y)
125 ]
126 geometry = zlayout.Polygon(vertices)
127
128 return CircuitComponent("Trace", geometry, "trace")
129
130
132 """Create a complex circuit layout with multiple components."""
133
134 # Define larger world bounds for complex circuit
135 world_bounds = zlayout.Rectangle(0, 0, 150, 100)
136 processor = zlayout.GeometryProcessor(world_bounds)
137
138 components = []
139
140 # Add microcontroller
141 mcu = create_microcontroller(30, 40)
142 components.append(mcu)
143 processor.add_component(mcu.geometry)
144
145 # Add resistors in various orientations
146 resistors = [
147 create_resistor(60, 50, 0), # Horizontal
148 create_resistor(75, 35, math.pi/2), # Vertical
149 create_resistor(90, 55, math.pi/4), # 45 degrees
150 create_resistor(20, 25, 0), # Near MCU
151 ]
152
153 for resistor in resistors:
154 components.append(resistor)
155 processor.add_component(resistor.geometry)
156
157 # Add capacitors
158 capacitors = [
159 create_capacitor(50, 25),
160 create_capacitor(70, 65),
161 create_capacitor(100, 40),
162 ]
163
164 for cap in capacitors:
165 components.append(cap)
166 processor.add_component(cap.geometry)
167
168 # Add traces connecting components
169 traces = [
170 # Connect MCU to resistors
171 create_trace(zlayout.Point(45, 47), zlayout.Point(54, 50), 0.2),
172 create_trace(zlayout.Point(37, 55), zlayout.Point(37, 65), 0.2),
173
174 # Connect resistors to capacitors
175 create_trace(zlayout.Point(66, 50), zlayout.Point(68, 65), 0.2),
176 create_trace(zlayout.Point(75, 45), zlayout.Point(98, 40), 0.2),
177
178 # Some traces that might cause narrow spacing issues
179 create_trace(zlayout.Point(85, 50), zlayout.Point(85, 60), 0.15),
180 create_trace(zlayout.Point(87, 50), zlayout.Point(87, 60), 0.15),
181 ]
182
183 for trace in traces:
184 components.append(trace)
185 processor.add_component(trace.geometry)
186
187 # Add some problematic geometries to test analysis
188
189 # Sharp angled component (connector)
190 sharp_connector = zlayout.Polygon([
191 zlayout.Point(110, 20),
192 zlayout.Point(125, 22),
193 zlayout.Point(112, 28), # This creates a sharp angle
194 zlayout.Point(108, 24)
195 ])
196 components.append(CircuitComponent("Connector", sharp_connector, "connector"))
197 processor.add_component(sharp_connector)
198
199 # Potentially intersecting components
200 overlap_poly1 = zlayout.Polygon([
201 zlayout.Point(15, 70),
202 zlayout.Point(25, 72),
203 zlayout.Point(23, 82),
204 zlayout.Point(13, 80)
205 ])
206
207 overlap_poly2 = zlayout.Polygon([
208 zlayout.Point(20, 75),
209 zlayout.Point(30, 77),
210 zlayout.Point(28, 87),
211 zlayout.Point(18, 85)
212 ])
213
214 components.extend([
215 CircuitComponent("Test1", overlap_poly1, "test"),
216 CircuitComponent("Test2", overlap_poly2, "test")
217 ])
218 processor.add_component(overlap_poly1)
219 processor.add_component(overlap_poly2)
220
221 return processor, components
222
223
225 """Analyze the layout for manufacturing constraints."""
226
227 print("=== Manufacturing Constraint Analysis ===\n")
228
229 # Different constraint levels for different processes
230 constraints = {
231 "prototype": {"min_spacing": 0.1, "min_trace_width": 0.1, "sharp_angle_limit": 20},
232 "standard": {"min_spacing": 0.15, "min_trace_width": 0.15, "sharp_angle_limit": 30},
233 "high_density": {"min_spacing": 0.05, "min_trace_width": 0.05, "sharp_angle_limit": 15}
234 }
235
236 for process_name, limits in constraints.items():
237 print(f"--- {process_name.upper()} PROCESS ---")
238
239 analysis = processor.analyze_layout(
240 sharp_angle_threshold=limits["sharp_angle_limit"],
241 narrow_distance_threshold=limits["min_spacing"]
242 )
243
244 # Check manufacturability
245 violations = 0
246
247 if analysis['sharp_angles']['count'] > 0:
248 violations += analysis['sharp_angles']['count']
249 print(f" ⚠️ Sharp angles: {analysis['sharp_angles']['count']} violations")
250
251 if analysis['narrow_distances']['count'] > 0:
252 violations += analysis['narrow_distances']['count']
253 print(f" ⚠️ Spacing violations: {analysis['narrow_distances']['count']}")
254 print(f" Minimum distance: {analysis['narrow_distances']['minimum']:.3f}")
255
256 if analysis['intersections']['polygon_pairs'] > 0:
257 violations += analysis['intersections']['polygon_pairs']
258 print(f" ❌ Intersections: {analysis['intersections']['polygon_pairs']} pairs")
259
260 if violations == 0:
261 print(f" ✅ Manufacturable with {process_name} process")
262 else:
263 print(f" ❌ {violations} total violations for {process_name} process")
264
265 print()
266
267 return processor.optimize_layout()
268
269
271 """Demonstrate design rule checking capabilities."""
272
273 print("=== Design Rule Checking (DRC) ===\n")
274
275 # Create processor with sample layout
276 processor, components = create_complex_circuit_layout()
277
278 # Run manufacturing analysis
279 optimization_results = analyze_manufacturing_constraints(processor)
280
281 # Component-specific analysis
282 print("--- COMPONENT ANALYSIS ---")
283
284 component_types = {}
285 for comp in components:
286 comp_type = comp.component_type
287 if comp_type not in component_types:
288 component_types[comp_type] = 0
289 component_types[comp_type] += 1
290
291 print("Component count by type:")
292 for comp_type, count in component_types.items():
293 print(f" {comp_type}: {count}")
294
295 print(f"\nTotal components: {len(components)}")
296
297 # Generate comprehensive report
298 print("\n--- DRC SUMMARY REPORT ---")
299 score = optimization_results['optimization_score']
300
301 if score >= 90:
302 status = "EXCELLENT"
303 emoji = "🟢"
304 elif score >= 70:
305 status = "GOOD"
306 emoji = "🟡"
307 elif score >= 50:
308 status = "ACCEPTABLE"
309 emoji = "🟠"
310 else:
311 status = "NEEDS WORK"
312 emoji = "🔴"
313
314 print(f"Overall Layout Quality: {emoji} {status} ({score:.1f}/100)")
315
316 print("\nRecommendations:")
317 for suggestion in optimization_results['suggestions']:
318 print(f" • {suggestion}")
319
320 if not optimization_results['suggestions']:
321 print(" ✅ No issues found! Layout meets all design rules.")
322
323 return processor, components, optimization_results
324
325
326def main():
327 """Main function demonstrating advanced EDA layout analysis."""
328
329 print("🔧 ZLayout - Advanced EDA Circuit Analysis")
330 print("=" * 60)
331
332 # Run design rule checking
333 processor, components, optimization_results = demonstrate_design_rule_checking()
334
335 # Generate visualizations
336 print("\n=== Visualization Generation ===")
337
338 try:
339 visualizer = zlayout.LayoutVisualizer(figsize=(16, 12))
340
341 # Extract just the geometries for visualization
342 polygons = [comp.geometry for comp in components if isinstance(comp.geometry, zlayout.Polygon)]
343
344 print("Creating circuit layout visualization...")
345 fig1 = visualizer.plot_layout(polygons, title="Complex Circuit Layout")
346
347 print("Creating DRC analysis visualization...")
348 fig2 = visualizer.plot_analysis_results(polygons, optimization_results['analysis'])
349
350 print("Creating optimization summary...")
351 fig3 = visualizer.plot_optimization_summary(optimization_results)
352
353 plt.show()
354
355 # Optionally save the results
356 save_option = input("\nSave analysis results and plots? (y/n): ").lower().strip()
357 if save_option == 'y':
358 # Save plots
359 visualizer.save_plots([fig1, fig2, fig3], "circuit_analysis")
360
361 # Save analysis to text file
362 with open("circuit_analysis_report.txt", "w") as f:
363 f.write("ZLayout Circuit Analysis Report\n")
364 f.write("=" * 40 + "\n\n")
365 f.write(f"Layout Quality Score: {optimization_results['optimization_score']:.1f}/100\n\n")
366
367 analysis = optimization_results['analysis']
368 f.write(f"Sharp Angles: {analysis['sharp_angles']['count']}\n")
369 f.write(f"Narrow Distances: {analysis['narrow_distances']['count']}\n")
370 f.write(f"Intersections: {analysis['intersections']['polygon_pairs']}\n\n")
371
372 f.write("Recommendations:\n")
373 for suggestion in optimization_results['suggestions']:
374 f.write(f" • {suggestion}\n")
375
376 print("Results saved to files!")
377
378 except ImportError:
379 print("Matplotlib not available. Install with: pip install matplotlib")
380
381 print("\n✅ Advanced EDA analysis completed!")
382
383
384if __name__ == "__main__":
385 main()
add_pin(self, zlayout.Point point, str pin_name="")
__init__(self, str name, geometry, str component_type="generic")
2D point with high-precision coordinates and utility methods
Definition point.hpp:23
Polygon class supporting both convex and concave polygons.
Definition polygon.hpp:25
Axis-aligned rectangle for bounding boxes and simple EDA components.
Definition rectangle.hpp:26
CircuitComponent create_capacitor(float x, float y)
CircuitComponent create_trace(zlayout.Point start, zlayout.Point end, float width=0.3)
CircuitComponent create_resistor(float x, float y, float rotation=0)
analyze_manufacturing_constraints(processor)
CircuitComponent create_microcontroller(float x, float y)