Download src/job_features.py from rasitcesur/Manufacturing-MoE: direct link, hf CLI and curl.
- Browser
- Download file 6.86 kB
-
https://huggingface.co/rasitcesur/Manufacturing-MoE/resolve/main/src/job_features.py
- Command line
-
hf download hf://rasitcesur/Manufacturing-MoE/src/job_features.py
-
curl -L -o job_features.py https://huggingface.co/rasitcesur/Manufacturing-MoE/resolve/main/src/job_features.py
6.86 kB
| """Job-level energy features (10 independently supervised subsystems). | |
| Inputs: complete G-code, machine profile, INFERENCE-PREDICTED command durations. | |
| Outputs: one feature vector and one physically integrated baseline Wh per device/JOB. | |
| No teacher duration or measured energy enters feature extraction. The physical | |
| integration uses command chronology to obtain duty/regime exposure, but does | |
| NOT make any neural energy prediction per G-code line. | |
| All feature engineering is based on known G-code, machine metadata, estimated | |
| motion time, and simulated (not observed) temperatures/duty. NOT calibrated. | |
| """ | |
| import json | |
| import numpy as np | |
| from physics import parse | |
| from component_power import COMPONENTS,DEFAULT_POWER,simulate_components,MOTION | |
| FEAT_NAMES={ | |
| 'electronics':['baseline_Wh','total_s','nominal_W','n_commands'], | |
| 'stepper_hold':['baseline_Wh','total_s','hold_active_s_est','nominal_W','n_commands'], | |
| 'motor_x':['baseline_Wh','motion_s','axis_mm_est','axis_mean_v','axis_rms_v','axis_peak_v','nominal_W','n_moves','total_s','accel_travel'], | |
| 'motor_y':['baseline_Wh','motion_s','axis_mm_est','axis_mean_v','axis_rms_v','axis_peak_v','nominal_W','n_moves','total_s','accel_travel'], | |
| 'motor_z':['baseline_Wh','motion_s','axis_mm_est','axis_mean_v','axis_rms_v','axis_peak_v','nominal_W','n_moves','total_s','accel_print'], | |
| 'motor_e':['baseline_Wh','motion_s','axis_mm_est','axis_mean_v','axis_rms_v','axis_peak_v','nominal_W','n_extrusion_moves','total_s','accel_print'], | |
| 'heater_nozzle':['baseline_Wh','total_s','nozzle_heating_s_est','target_temp_s','setpoint_mean_C','start_C','ambient_C','nominal_W','thermal_capacity','thermal_loss','fan_level_s','n_target_changes','extrusion_mm'], | |
| 'heater_bed':['baseline_Wh','total_s','bed_heating_s_est','target_temp_s','setpoint_mean_C','start_C','ambient_C','nominal_W','thermal_capacity','thermal_loss','n_target_changes'], | |
| 'fan_part':['baseline_Wh','total_s','fan_pwm_time_s','fan_active_s','nominal_W','fan_transition_n'], | |
| 'fan_hotend':['baseline_Wh','total_s','hotend_on_time_s_est','nominal_W','nozzle_target_time_Cs','nozzle_start_C'], | |
| } | |
| # Feature magnitudes are log1p transformed, except unscaled temperatures may be | |
| # zero or negative. Train-only scalers are used afterward. | |
| def summary(rows,durations): | |
| t=np.asarray(durations,dtype=np.float64).reshape(-1) | |
| if len(t)!=len(rows) or len(rows)==0 or not np.all(np.isfinite(t)) or np.any(t<0): | |
| raise ValueError('Invalid sequence durations') | |
| profile=json.loads(rows[0]['initial_profile']) if isinstance(rows[0]['initial_profile'],str) else rows[0]['initial_profile'] | |
| hw={**DEFAULT_POWER,**profile.get('power_hardware',{})} | |
| energy_line,power_line,vel=simulate_components(rows,t) | |
| base=np.asarray(energy_line,dtype=np.float64).sum(axis=0) | |
| assert base.shape==(len(COMPONENTS),) | |
| commands=[parse(r['gcode']) for r in rows] | |
| move=np.asarray([c in MOTION for c,_ in commands]) | |
| nmove=int(move.sum());total=float(t.sum());move_s=float(t[move].sum()) | |
| axis_len=np.sum(vel*t[:,None],axis=0) | |
| axis_mean=np.sum(vel*t[:,None],axis=0)/max(1.e-8,move_s) | |
| axis_rms=np.sqrt(np.sum(vel**2*t[:,None],axis=0)/max(1.e-8,move_s)) | |
| axis_max=np.max(vel,axis=0) | |
| # G-code state-history (setpoint & PWM); no labels or sensor truth involved. | |
| noz_sp=float(profile.get('nozzle_start',profile.get('ambient',23))) | |
| bed_sp=float(profile.get('bed_start',profile.get('ambient',23))) | |
| fan=float(profile.get('fan_start',0.)) | |
| fan_pwm_s=fan_s=noz_sp_time=bed_sp_time=0. | |
| n_noz=n_bed=n_fan=0 | |
| noz_heating_s=bed_heating_s=hotend_on_s=0. | |
| for (c,a),dt,wh in zip(commands,t,energy_line): | |
| if c in ('M104','M109'): | |
| nxt=float(a.get('S',a.get('R',noz_sp))) | |
| n_noz+=int(abs(nxt-noz_sp)>1e-8);noz_sp=nxt | |
| if c in ('M140','M190'): | |
| nxt=float(a.get('S',a.get('R',bed_sp))) | |
| n_bed+=int(abs(nxt-bed_sp)>1e-8);bed_sp=nxt | |
| if c=='M106': | |
| nxt=max(0.,min(255.,a.get('S',255.)));n_fan+=int(abs(fan-nxt)>1e-8);fan=nxt | |
| if c=='M107': | |
| n_fan+=int(fan>0);fan=0. | |
| noz_sp_time+=noz_sp*dt | |
| bed_sp_time+=bed_sp*dt | |
| fan_pwm_s+=dt*fan/255. | |
| fan_s+=dt*(fan>0) | |
| # Estimated energy exposure, from reference physics, not measured label. | |
| noz_heating_s+=float(wh[COMPONENTS.index('heater_nozzle')])*3600/max(hw['nozzle_w'],1.e-7) | |
| bed_heating_s+=float(wh[COMPONENTS.index('heater_bed')])*3600/max(hw['bed_w'],1.e-7) | |
| hotend_on_s+=float(wh[COMPONENTS.index('fan_hotend')])*3600/max(hw['hotend_fan_w'],1.e-7) | |
| hold_s=base[1]*3600/max(hw['stepper_hold_w'],1.e-7) | |
| shared={} | |
| shared['electronics']=[base[0],total,hw['electronics_w'],len(t)] | |
| shared['stepper_hold']=[base[1],total,hold_s,hw['stepper_hold_w'],len(t)] | |
| for i,k in enumerate(['motor_x','motor_y','motor_z','motor_e']): | |
| kk=('x','y','z','e')[i] | |
| nominal=hw[f'{kk}_motor_w_at_'+('60' if i<2 else '5')] | |
| shared[k]=[base[2+i],move_s,axis_len[i],axis_mean[i],axis_rms[i],axis_max[i],nominal, | |
| int((vel[:,i]>0).sum()) if i==3 else nmove,total, | |
| float(profile.get('accel_travel' if i<2 else 'accel_print',500))] | |
| shared['heater_nozzle']=[base[6],total,noz_heating_s,noz_sp_time, | |
| noz_sp_time/max(total,1.e-8),float(profile['nozzle_start']),float(profile['ambient']),hw['nozzle_w'], | |
| hw['nozzle_cap_j_c'],hw['nozzle_loss_w_c'],fan_pwm_s,n_noz,axis_len[3]] | |
| shared['heater_bed']=[base[7],total,bed_heating_s,bed_sp_time, | |
| bed_sp_time/max(total,1.e-8),float(profile['bed_start']),float(profile['ambient']),hw['bed_w'], | |
| hw['bed_cap_j_c'],hw['bed_loss_w_c'],n_bed] | |
| shared['fan_part']=[base[8],total,fan_pwm_s,fan_s,hw['part_fan_w'],n_fan] | |
| shared['fan_hotend']=[base[9],total,hotend_on_s,hw['hotend_fan_w'],noz_sp_time,float(profile['nozzle_start'])] | |
| features={k:np.asarray(shared[k],dtype=np.float32) for k in COMPONENTS} | |
| for k in COMPONENTS: | |
| if len(features[k])!=len(FEAT_NAMES[k]):raise AssertionError(k) | |
| if not np.all(np.isfinite(features[k])):raise ValueError('Nonfinite feature '+k) | |
| return {'x':features,'base':base.astype('float32'),'time_s':total, | |
| 'n_moves':nmove, | |
| 'regimes':{'motion_time_s':move_s,'heater_nozzle_s_est':noz_heating_s,'heater_bed_s_est':bed_heating_s, | |
| 'fan_pwm_equiv_s':fan_pwm_s,'axis_distance_mm_est':axis_len.tolist()}} | |
| def fit_scalers(examples): | |
| return {k:(np.stack([e['summary']['x'][k] for e in examples]).mean(0).astype('float32'), | |
| np.maximum(np.stack([e['summary']['x'][k] for e in examples]).std(0),.001).astype('float32')) | |
| for k in COMPONENTS} | |
| def normalized(x,scalers): | |
| return {k:np.clip((x[k]-scalers[k][0])/scalers[k][1],-8,8).astype('float32') for k in COMPONENTS} | |