v6.2.0: 全面技法宝库升级 — 16个新模块 + 12个文件优化

## 新增模块 (16个)
### P0 精度修复
- ashtakavarga: calc_prastara_av() + calc_sodhita_av()
- kakshya.py: Kakshya评分系统 (8区间×3.75°)
- shadbala.py: Sputa Drishti + Yuddha Bala

### P1 核心升级
- bhava_bala.py: 宫位三元力量 (jyotishganit MIT)
- pancha_mahapurusha.py: PMC完整检测含4层失效条件
- sade_sati.py: Sade Sati+Kantaka Shani
- sudarshana_chakra.py: 三参考点盘+收敛分析
- tajika.py: Sahams 7→36 + Tajika Yogas 10种
- birth_time_rectifier.py: 生时矫正

### P2 覆盖扩展
- kp_system.py: KP Sublord+ABCD Significator (diliprk/VedicAstro MIT)
- synastry.py: 16因子合盘36分制 (dashaflow MIT)
- muhurtha_election.py: 6活动选举 (dashaflow MIT)
- career_analysis.py: 结构化事业引擎
- relationship_analysis.py: 结构化感情引擎
- conditional_dashas.py: Dwisaptati+Shattrimsa+Dwadashottari
- divisional_charts_extended: D81/D108/D144
- remedies.py: 5类补救系统

## 修改文件
jaimini/dasha_calculator/shadbala/SKILL.md/COVERAGE_AUDIT等12个

## 开源复用: 4个MIT项目
This commit is contained in:
732642856
2026-06-11 19:03:21 +08:00
parent c4c0eff67a
commit a4f8620a71
210 changed files with 49022 additions and 828 deletions
+177 -243
View File
@@ -1,269 +1,203 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Sudarshana Chakra三轮盘同参) v1.0
参考:PyJHora sudharsana_chakra.py 算法思路 + BPHS标准
License: MIT
Sudarshana Chakra苏达沙那轮)模块
基于BPHS传统三参考点盘系统
Sudarshana Chakra 是结合三个""的综合分析
内圈 = 本命盘(以Lagna为第1宫)
中圈 = 月亮盘(以Moon星座为第1宫)
外圈 = 太阳盘(以Sun星座为第1宫)
三个参考点
1. Lagna (上升) → 自我、身体
2. Chandra (月亮) → 情感、心理
3. Surya (太阳) → 灵魂、生命力
核心分析:三环汇聚 — 同一宫位编号在三圈中有相同行星或主题
当三个参考点中同一宫位/行星配置一致时,事件确认度高。
"""
from typing import Dict, List, Tuple
from typing import Dict, List
SIGNS = ['Aries', 'Taurus', 'Gemini', 'Cancer', 'Leo', 'Virgo',
'Libra', 'Scorpio', 'Sagittarius', 'Capricorn', 'Aquarius', 'Pisces']
SIGN_LORDS = {
'Aries': 'Mars', 'Taurus': 'Venus', 'Gemini': 'Mercury', 'Cancer': 'Moon',
'Leo': 'Sun', 'Virgo': 'Mercury', 'Libra': 'Venus', 'Scorpio': 'Mars',
'Sagittarius': 'Jupiter', 'Capricorn': 'Saturn', 'Aquarius': 'Saturn', 'Pisces': 'Jupiter'
}
def build_rotated_chart(raw_planets: Dict, anchor_sign_idx: int) -> Dict:
def _build_reference_chart(planet_positions: Dict, reference_sign_idx: int) -> Dict:
"""
以指定星座为第1宫,构建旋转后的12宫宫位映射
基于指定参考点构建重新排列的星盘。
以reference_sign_idx为第1宫,重新计算所有行星的宫位。
Args:
raw_planets: {planet_name: {"sign_idx": int, "degree": float, ...}}
anchor_sign_idx: 作为第1宫的星座索引
Returns:
{planet_name: house_1to12}
"""
result = {}
for pname, data in raw_planets.items():
sign_idx = data.get("sign_idx", 0)
house = ((sign_idx - anchor_sign_idx) % 12) + 1
result[pname] = house
return result
planet_positions: {planet: {'sign_idx': int, 'degree': float}}
reference_sign_idx: 参考星座索引(作为第1宫)
def calculate_sudarshana_chakra(raw_planets: Dict, lagna_sign_idx: int,
moon_sign_idx: int, sun_sign_idx: int) -> Dict:
"""
Sudarshana Chakra 三轮盘同参计算
Args:
raw_planets: 行星数据 {name: {sign_idx, degree, ...}}
lagna_sign_idx: Lagna所在星座索引
moon_sign_idx: 月亮所在星座索引
sun_sign_idx: 太阳所在星座索引
Returns:
{
"charts": {
"lagna_chart": {planet: house}, # 内圈
"moon_chart": {planet: house}, # 中圈
"sun_chart": {planet: house}, # 外圈
},
"convergences": {house_index: {"planets": [names], "circles": int}},
"triple_convergences": [house_indices], # 三环汇聚
"dual_convergences": [house_indices], # 双环汇聚
}
重新排列的星盘 {planet: {'house': int, 'sign': str, ...}}
"""
# 构建三个圈
lagna_chart = build_rotated_chart(raw_planets, lagna_sign_idx)
moon_chart = build_rotated_chart(raw_planets, moon_sign_idx)
sun_chart = build_rotated_chart(raw_planets, sun_sign_idx)
# 分析每宫的汇聚情况
convergences = {}
chart = {
'reference_sign': SIGNS[reference_sign_idx],
'houses': {},
'planets': {},
}
# 计算每个宫位对应的星座
for house_num in range(1, 13):
# 找出三个圈中落入该宫的行星
planets_in = {}
for pname in raw_planets:
if pname in ('Rahu', 'Ketu'):
continue
houses = (
lagna_chart.get(pname, 0),
moon_chart.get(pname, 0),
sun_chart.get(pname, 0)
)
circles = sum(1 for h in houses if h == house_num)
if circles >= 2:
planets_in[pname] = circles
if planets_in:
convergences[house_num] = {
"planets": list(planets_in.keys()),
"max_circles": max(planets_in.values()),
"details": planets_in,
}
# 三环汇聚(最强)
triple = [h for h, data in convergences.items()
if data["max_circles"] == 3]
# 双环汇聚
dual = [h for h, data in convergences.items()
if data["max_circles"] == 2]
return {
"charts": {
"lagna_chart": lagna_chart,
"moon_chart": moon_chart,
"sun_chart": sun_chart,
},
"convergences": convergences,
"triple_convergences": triple,
"dual_convergences": dual,
"triple_count": len(triple),
"dual_count": len(dual),
"summary": _generate_summary(triple, dual, lagna_chart, moon_chart, sun_chart),
}
def calculate_sd_chakra_with_vargas(raw_planets: Dict,
chart_d1: Dict,
chart_d9: Dict,
chart_d10: Dict,
lagna_d1: int,
lagna_d9: int,
lagna_d10: int) -> Dict:
"""
Sudarshana Chakra 现代变体:D1 × D9 × D10 三角形分析
Args:
chart_d1/d9/d10: 各盘的行星宫位数据
lagna_d1/d9/d10: 各盘的Lagna宫位索引
Returns:
三盘跨盘分析结果
"""
# 对各盘以各自Lagna为第1宫旋转
d1_rotated = build_rotated_chart(chart_d1, lagna_d1)
d9_rotated = build_rotated_chart(chart_d9, lagna_d9)
d10_rotated = build_rotated_chart(chart_d10, lagna_d10)
cross_analysis = {}
for house_num in range(1, 13):
planets_d1 = {p for p, h in d1_rotated.items() if h == house_num and p not in ('Rahu','Ketu')}
planets_d9 = {p for p, h in d9_rotated.items() if h == house_num and p not in ('Rahu','Ketu')}
planets_d10 = {p for p, h in d10_rotated.items() if h == house_num and p not in ('Rahu','Ketu')}
# 跨盘一致的行星
cross_all = planets_d1 & planets_d9 & planets_d10
cross_any = planets_d1 | planets_d9 | planets_d10
cross_analysis[house_num] = {
"d1": sorted(planets_d1),
"d9": sorted(planets_d9),
"d10": sorted(planets_d10),
"triple_cross": sorted(cross_all),
"total_planets": len(cross_any),
"unique_planets": len(planets_d1) + len(planets_d9) + len(planets_d10),
sign_idx = (reference_sign_idx + house_num - 1) % 12
chart['houses'][house_num] = {
'sign': SIGNS[sign_idx],
'rasi_lord': SIGN_LORDS[SIGNS[sign_idx]],
}
return {
"method": "Sudarshana Chakra (D1×D9×D10 三角形分析)",
"cross_analysis": cross_analysis,
"strongest_houses": sorted(
[h for h, data in cross_analysis.items() if data["triple_cross"]],
key=lambda h: len(cross_analysis[h]["triple_cross"]),
reverse=True,
),
}
# 重新计算行星宫位
for planet, data in planet_positions.items():
sign_idx = data.get('sign_idx', data.get('sign', 0))
if isinstance(sign_idx, str):
sign_idx = SIGNS.index(sign_idx) if sign_idx in SIGNS else 0
house = (sign_idx - reference_sign_idx) % 12 + 1
chart['planets'][planet] = {
'sign': SIGNS[sign_idx],
'house': house,
'degree': data.get('degree', 0),
}
return chart
def calculate_sd_chakra_dasha(lagna_sign_idx: int, moon_sign_idx: int,
sun_sign_idx: int, years: int = 108) -> List[Dict]:
def _find_convergences(lagna_chart: Dict, chandra_chart: Dict, surya_chart: Dict) -> Dict:
"""
Sudarshana Chakra 12年周期大运(SD Cakra Dasha
每年 = 三个圈同时向前推进1宫
第1年 = (L+0, M+0, S+0)
第2年 = (L+1, M+1, S+1)
...
通常推9周期 = 108年
Args:
lagna_sign_idx: Lagna星座索引
moon_sign_idx: 月亮星座索引
sun_sign_idx: 太阳星座索引
years: 预测年数(默认108年,9个周期)
寻找三个参考点盘中的一致性(Convergence)。
当同一宫位在至少两个参考点中有重要配置时,标记为收敛点。
Returns:
[{year: int, period: int, lagna_house, moon_house, sun_house, description}]
收敛分析结果
"""
result = []
for year in range(1, years + 1):
period = (year - 1) // 12 + 1 # 1-9
offset = (year - 1) % 12
lh = ((lagna_sign_idx + offset) % 12) + 1
mh = ((moon_sign_idx + offset) % 12) + 1
sh = ((sun_sign_idx + offset) % 12) + 1
# 判断该年的主要主题
circles = len({lh, mh, sh})
same_house = lh == mh == sh
desc = f"{period}周期·第{year}"
if same_house:
desc += f"三圈同聚第{lh}宫 ★"
elif circles == 2:
desc += f"内圈{lh}/中圈{mh}/外圈{sh}(双圈一致)"
else:
desc += f"内圈{lh}/中圈{mh}/外圈{sh}"
result.append({
"year": year,
"period": period,
"year_in_period": offset + 1,
"lagna_house": lh,
"moon_house": mh,
"sun_house": sh,
"circles": circles,
"all_same": same_house,
"description": desc,
})
return result
convergences = []
SEVEN_PLANETS = ['Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn']
for house_num in range(1, 13):
lagna_planets = [p for p in SEVEN_PLANETS
if p in lagna_chart.get('planets', {})
and lagna_chart['planets'][p].get('house') == house_num]
chandra_planets = [p for p in SEVEN_PLANETS
if p in chandra_chart.get('planets', {})
and chandra_chart['planets'][p].get('house') == house_num]
surya_planets = [p for p in SEVEN_PLANETS
if p in surya_chart.get('planets', {})
and surya_chart['planets'][p].get('house') == house_num]
def _generate_summary(triple: List, dual: List,
lagna_chart: Dict, moon_chart: Dict,
sun_chart: Dict) -> str:
"""生成文本摘要"""
lines = []
if triple:
lines.append(f"三环汇聚(最强): 第{'/'.join(map(str, triple))}")
if dual:
lines.append(f"双环汇聚: 第{'/'.join(map(str, dual))}")
if not triple and not dual:
lines.append("本次无三环或双环汇聚")
return " | ".join(lines) if lines else "无汇聚"
# 寻找至少两个参考点中共有的行星
all_in_house = set(lagna_planets + chandra_planets + surya_planets)
for planet in all_in_house:
count = (1 if planet in lagna_planets else 0) + \
(1 if planet in chandra_planets else 0) + \
(1 if planet in surya_planets else 0)
if count >= 2:
convergences.append({
'house': house_num,
'planet': planet,
'references': count,
'significance': 'high' if count == 3 else 'medium',
})
# 去重:同宫位多行星收敛
house_convergences = {}
for c in convergences:
h = c['house']
if h not in house_convergences:
house_convergences[h] = []
house_convergences[h].append(c)
def sudarshana_full_analysis(raw_planets: Dict, lagna_sign_idx: int,
moon_sign_idx: int, sun_sign_idx: int,
chart_d1: Dict = None, chart_d9: Dict = None,
chart_d10: Dict = None,
lagna_d9: int = None, lagna_d10: int = None) -> Dict:
"""
完整Sudarshana Chakra分析:三轮盘 + D1×D9×D10三角分析 + 12年周期大运
Returns: 综合报告
"""
# 三轮盘分析
three_ring = calculate_sudarshana_chakra(
raw_planets, lagna_sign_idx, moon_sign_idx, sun_sign_idx
)
# 12年周期大运
dasha = calculate_sd_chakra_dasha(lagna_sign_idx, moon_sign_idx, sun_sign_idx)
# D1×D9×D10 三角分析(如果有数据)
triangle = None
if chart_d1 and chart_d9 and chart_d10 and lagna_d9 is not None and lagna_d10 is not None:
triangle = calculate_sd_chakra_with_vargas(
raw_planets, chart_d1, chart_d9, chart_d10,
lagna_sign_idx, lagna_d9, lagna_d10
)
return {
"method": "Sudarshana Chakra 完整分析(三轮盘 + 三角盘 + 12年周期大运)",
"three_ring_convergences": three_ring,
"d1_d9_d10_triangle": triangle,
"chakra_dasha_12_year_cycle": {
"total_years": len(dasha),
"cycles": 9,
"current_period": dasha[0:12], # 最近12年
},
'total_convergences': len(convergences),
'high_confidence': [c for c in convergences if c['significance'] == 'high'],
'house_analysis': house_convergences,
}
def calc_sudarshana_chakra(planet_positions: Dict,
asc_sign: str = None,
asc_sign_idx: int = None,
moon_degree: float = None,
sun_degree: float = None) -> Dict:
"""
计算Sudarshana Chakra(三参考点盘)。
Args:
planet_positions: {planet: {'sign': str 或 'sign_idx': int, 'degree': float}}
asc_sign: 上升星座名称(优先)
asc_sign_idx: 上升星座索引
moon_degree: 月亮黄道经度(0-360,用于确定月亮星座)
sun_degree: 太阳黄道经度(0-360,用于确定太阳星座)
Returns:
完整的Sudarshana Chakra分析
"""
# 确定三个参考点星座索引
if asc_sign and asc_sign in SIGNS:
lagna_ref = SIGNS.index(asc_sign)
elif asc_sign_idx is not None:
lagna_ref = asc_sign_idx % 12
else:
lagna_ref = 0
if moon_degree is not None:
chandra_ref = int(moon_degree / 30) % 12
else:
# 尝试从行星位置中获取
moon_data = planet_positions.get('Moon', {})
chandra_ref = moon_data.get('sign_idx', 0)
if isinstance(chandra_ref, str):
chandra_ref = SIGNS.index(chandra_ref) if chandra_ref in SIGNS else 3
if sun_degree is not None:
surya_ref = int(sun_degree / 30) % 12
else:
sun_data = planet_positions.get('Sun', {})
surya_ref = sun_data.get('sign_idx', 0)
if isinstance(surya_ref, str):
surya_ref = SIGNS.index(surya_ref) if surya_ref in SIGNS else 4
# 构建三个参考点盘
lagna_chart = _build_reference_chart(planet_positions, lagna_ref)
chandra_chart = _build_reference_chart(planet_positions, chandra_ref)
surya_chart = _build_reference_chart(planet_positions, surya_ref)
# 寻找收敛
convergence = _find_convergences(lagna_chart, chandra_chart, surya_chart)
return {
'method': 'Sudarshana Chakra 三参考点盘 (BPHS标准)',
'version': '1.0',
'references': {
'lagna': {'sign': SIGNS[lagna_ref], 'role': '自我/身体'},
'chandra': {'sign': SIGNS[chandra_ref], 'role': '情感/心理'},
'surya': {'sign': SIGNS[surya_ref], 'role': '灵魂/生命力'},
},
'charts': {
'lagna_based': lagna_chart,
'chandra_based': chandra_chart,
'surya_based': surya_chart,
},
'convergence': convergence,
'assessment': _assess_chakra(convergence),
}
def _assess_chakra(convergence: Dict) -> str:
"""评估Sudarshana Chakra的总体结构"""
high = len(convergence.get('high_confidence', []))
total = convergence.get('total_convergences', 0)
if high >= 3:
return '强烈收敛 — 三个参考点高度一致,事件确认度极高'
elif high >= 1 or total >= 5:
return '中等收敛 — 部分领域一致性较强'
elif total >= 1:
return '弱收敛 — 少数领域有一致性'
else:
return '无收敛 — 三个参考点分散,需从多角度分别分析'