修复循环信号与事件采样并接入 LSTP 接触定位,补充八路验证及复用实验
相较上一版 Jacobian 确定性复用更新,本次补齐事件边界一致性、结果两侧采样及接触事件定位;保留已有物性复用和组件力学公式。 - 统一 UD00 信号求值与下一事件查询的绝对时间边界,修复循环边界浮点舍入导致的阶段错位、重复或漏报,并覆盖零时长、多阶段及长周期场景。 - 引入原生输出语义 v2:保留规则网格真实时间,补充内部时间事件和状态事件的左邻及事件后采样,按保存时间、状态和离散模式重放结果。 - 两条代码生成路径均发出 LSTP 接触描述,默认定位间隙过零及非负力模式的力截断;仅在接受事件时更新防重复记录,增加 contactEvents 诊断计数。 - 补充 MASS/LSTP 独立事件实验、八路全曲线与驱动阶段配对评估,以及 Amesim 不连续点输出对照和力差定位报告;MASS 新增释放机制仍保留为独立实验。 - 保存局部 probe、context 访问与回退、shadow replay、R288 real skip/typed replay 及阀门数值尾部诊断工具和报告;未证明净收益的实验不启用为生产默认优化。 - 更新原生运行说明和元件建模规范,补充信号边界、输出语义、接触事件和实验依赖回归测试。 验证:五组专项回归共 34 项全部通过;37 个待提交 Python 文件语法检查通过;git diff --cached --check 通过。
This commit is contained in:
1 parent
1aac220084
commit
7611f13208
85 files changed
+11358
-33
No files matched your search
@@ -1,37 +1,81 @@
|
||||
#include "kernels.h"
|
||||
#include <math.h>
|
||||
|
||||
double native_signal(double t, double start, int stages, int cyclic, const double *data) {
|
||||
if (t < start) return data[0];
|
||||
double elapsed = t-start, duration = 0, offset = 0;
|
||||
for (int i=0;i<stages;i++) duration += data[16+i];
|
||||
if (cyclic && duration > 0) elapsed = fmod(elapsed,duration);
|
||||
else if (elapsed >= duration) return data[8+stages-1];
|
||||
for (int i=0;i<stages;i++) {
|
||||
double d = data[16+i];
|
||||
if (elapsed < offset+d || i == stages-1)
|
||||
return d <= 0 ? data[8+i] : data[i] + (elapsed-offset)/d*(data[8+i]-data[i]);
|
||||
offset += d;
|
||||
typedef struct {
|
||||
int stage;
|
||||
double begin, next;
|
||||
} SignalInterval;
|
||||
|
||||
/* Both queries must construct exactly the same absolute boundary. In
|
||||
* particular, fmod(t-start,period) can still be below a stage offset at the
|
||||
* double returned by the event query (e.g. 44 s for periods of .8+10 s). */
|
||||
static double signal_boundary(double start, double offset, double cycle, double period) {
|
||||
return cycle==0 ? start+offset : (start+offset)+cycle*period;
|
||||
}
|
||||
|
||||
static int signal_cycle(double t, double start, double period, double *current, double *next) {
|
||||
double lo=fmax(0,floor((t-start)/period));
|
||||
if (!isfinite(lo)) return 0;
|
||||
double hi=fmax(lo+1,nextafter(lo,INFINITY));
|
||||
if (signal_boundary(start,0,lo,period)>t) {
|
||||
hi=lo; lo=fmax(0,hi-1);
|
||||
if (signal_boundary(start,0,lo,period)>t) lo=0;
|
||||
} else {
|
||||
/* Usually hi=lo+1 already brackets t. At coarse time resolution,
|
||||
* several cycles can round to the same double: bracket/bisect them
|
||||
* rather than advancing one cycle at a time or shifting t. */
|
||||
while (signal_boundary(start,0,hi,period)<=t) {
|
||||
lo=hi; hi=fmax(2*hi,nextafter(hi,INFINITY));
|
||||
if (!isfinite(hi)) return 0;
|
||||
}
|
||||
}
|
||||
return data[8+stages-1];
|
||||
for (;;) {
|
||||
double mid=floor(lo+(hi-lo)/2);
|
||||
if (mid<=lo || mid>=hi) break;
|
||||
if (signal_boundary(start,0,mid,period)<=t) lo=mid;
|
||||
else hi=mid;
|
||||
}
|
||||
*current=lo; *next=hi;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SignalInterval signal_interval(double t, double start, int stages, int cyclic,
|
||||
const double *data) {
|
||||
if (t<start) return (SignalInterval){-1,start,start};
|
||||
double offsets[9]={0};
|
||||
for (int i=0;i<stages;i++) offsets[i+1]=offsets[i]+data[16+i];
|
||||
double period=offsets[stages], cycle=0, next_cycle=0;
|
||||
cyclic=cyclic && period>0 && isfinite(period);
|
||||
if (cyclic && !signal_cycle(t,start,period,&cycle,&next_cycle))
|
||||
return (SignalInterval){-2,NAN,NAN};
|
||||
for (int i=0;i<stages;i++) {
|
||||
/* A cycle's last endpoint is the next cycle's first boundary,
|
||||
* never a separately rounded (start+period)+cycle*period. */
|
||||
double right=cyclic && offsets[i+1]==period ? signal_boundary(start,0,next_cycle,period) :
|
||||
signal_boundary(start,offsets[i+1],cycle,period);
|
||||
if (t<right)
|
||||
return (SignalInterval){i,signal_boundary(start,offsets[i],cycle,period),right};
|
||||
}
|
||||
return (SignalInterval){stages,0,INFINITY};
|
||||
}
|
||||
|
||||
double native_signal(double t, double start, int stages, int cyclic, const double *data) {
|
||||
SignalInterval interval=signal_interval(t,start,stages,cyclic,data);
|
||||
if (interval.stage==-2) return NAN;
|
||||
if (interval.stage==-1) return data[0];
|
||||
if (interval.stage==stages) return data[8+stages-1];
|
||||
int i=interval.stage;
|
||||
double d=data[16+i];
|
||||
if (d<=0) return data[8+i];
|
||||
double fraction=fmin(1,fmax(0,(t-interval.begin)/d));
|
||||
if (fraction==0) return data[i];
|
||||
if (fraction==1) return data[8+i];
|
||||
return data[i]+fraction*(data[8+i]-data[i]);
|
||||
}
|
||||
|
||||
double native_signal_break(double t, double end, double start, int stages,
|
||||
int cyclic, const double *data) {
|
||||
double duration=0, offset=0, result=end;
|
||||
for (int i=0;i<stages;i++) duration += data[16+i];
|
||||
/* A cyclic endpoint is already the next cycle's start. Listing both can
|
||||
create two nearly equal floating-point break times for one event. */
|
||||
for (int i=0;i<stages+(cyclic?0:1);i++) {
|
||||
double event=start+offset;
|
||||
if (cyclic && duration > 0 && event <= t) {
|
||||
double cycle=fmax(0,floor((t-event)/duration)+1);
|
||||
event += cycle*duration;
|
||||
if (event <= t) event += duration;
|
||||
}
|
||||
if (event > t) result=fmin(result,event);
|
||||
if (i < stages) offset += data[16+i];
|
||||
}
|
||||
return result;
|
||||
SignalInterval interval=signal_interval(t,start,stages,cyclic,data);
|
||||
return interval.stage==-2 ? NAN : fmin(end,interval.next);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user