emc_compare_limits
Compare FCC and CISPR emission limits at a specified frequency and device class to identify the more restrictive standard.
Instructions
Compare emission limits between FCC and CISPR standards at a given frequency.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| frequency_mhz | Yes | Frequency in MHz | |
| device_class | No | Device class |
Implementation Reference
- The _compare_limits static method is the core handler for the emc_compare_limits tool. It looks up FCC Part 15.109 limits and CISPR 32 limits for the given frequency and device class, formats a comparison, and includes a distance-correction note (10.5 dB to convert 10m→3m).
@staticmethod def _compare_limits(arguments: dict[str, Any]) -> list[TextContent]: freq_mhz = arguments["frequency_mhz"] device_class = arguments.get("device_class", "B").upper() result = f"EMC Limit Comparison at {freq_mhz} MHz (Class {device_class})\n{'=' * 55}\n\n" fcc_data = PART15_LIMITS.get("section_15_109", {}).get(f"class_{device_class.lower()}", {}) fcc_limit = find_limit_for_frequency(fcc_data.get("limits", []), freq_mhz) if fcc_limit: result += f"FCC Part 15.109 Class {device_class}:\n" result += f" {fcc_limit['limit_dbuv_m']} dBuV/m @ {fcc_limit['distance_m']}m (QP)\n\n" cispr_data = CISPR_LIMITS.get("cispr_32", {}).get(f"class_{device_class.lower()}", {}) cispr_rad = cispr_data.get("radiated_emissions", {}) cispr_limit = find_limit_for_frequency(cispr_rad.get("limits", []), freq_mhz) if cispr_limit: result += f"CISPR 32 Class {device_class}:\n" result += f" {cispr_limit['limit_dbuv_m']} dBuV/m @ {cispr_rad.get('measurement_distance_m', 10)}m (QP)\n\n" if fcc_limit and cispr_limit: result += "Note: FCC uses 3m, CISPR uses 10m measurement distance.\n" result += "Distance correction: +10.5 dB to convert 10m\u21923m limits.\n" cispr_at_3m = cispr_limit["limit_dbuv_m"] + 10.5 result += f"CISPR 32 at 3m (calculated): {cispr_at_3m:.1f} dBuV/m\n" return [TextContent(type="text", text=result)] - The Tool definition for emc_compare_limits defines the input schema: required 'frequency_mhz' (number) and optional 'device_class' with enum ['A', 'B'] defaulting to 'B'.
Tool( name="emc_compare_limits", description="Compare emission limits between FCC and CISPR standards at a given frequency.", inputSchema={ "type": "object", "properties": { "frequency_mhz": {"type": "number", "description": "Frequency in MHz"}, "device_class": {"type": "string", "enum": ["A", "B"], "description": "Device class"}, }, "required": ["frequency_mhz"], }, ), - src/mcp_emc_regulations/tools/comparison.py:39-44 (registration)The call_tool dispatcher in ComparisonTools routes the name 'emc_compare_limits' to the _compare_limits handler. This is the MCP tool dispatch point.
async def call_tool(self, name: str, arguments: dict[str, Any]) -> list[TextContent]: if name == "emc_compare_limits": return self._compare_limits(arguments) elif name == "emc_standards_list": return self._standards_list() return [TextContent(type="text", text=f"Unknown comparison tool: {name}")] - src/mcp_emc_regulations/registry.py:41-52 (registration)ToolRegistry._discover() auto-discovers ToolModule subclasses (like ComparisonTools) from the tools package, so the tool is automatically registered without manual wiring.
def _discover(self) -> None: """Import every module in the ``tools`` package and instantiate ToolModules.""" for info in pkgutil.iter_modules(_tools_pkg.__path__, _tools_pkg.__name__ + "."): module = importlib.import_module(info.name) for attr_name in dir(module): attr = getattr(module, attr_name) if ( isinstance(attr, type) and issubclass(attr, ToolModule) and attr is not ToolModule ): self._modules.append(attr()) - find_limit_for_frequency is a utility used by _compare_limits to look up the applicable limit entry from a list of frequency ranges for a given frequency.
def find_limit_for_frequency(limits: list, freq_mhz: float) -> dict | None: """Find the applicable limit entry for a given frequency. Tries half-open intervals [min, max) first, then falls back to closed intervals [min, max] so upper-bound edge cases are not missed. """ for limit in limits: if limit["freq_min_mhz"] <= freq_mhz < limit["freq_max_mhz"]: return limit for limit in limits: if limit["freq_min_mhz"] <= freq_mhz <= limit["freq_max_mhz"]: return limit return None