diff --git a/roadscore/prototype/motion_presentation.py b/roadscore/prototype/motion_presentation.py index 2c2b0643b8..c62b343cde 100644 --- a/roadscore/prototype/motion_presentation.py +++ b/roadscore/prototype/motion_presentation.py @@ -12,8 +12,9 @@ class MotionPresentation: def process(self, pcm, *, speed, source_fresh, engagement_open_mix=1.): dt=len(pcm)/self.rate - self.fresh=bool(source_fresh and math.isfinite(speed) and speed>=0.) + self.fresh=bool(source_fresh and math.isfinite(speed) and speed>=-.05) if self.fresh: + speed=max(0.,speed) self.stop_seconds=self.stop_seconds+dt if speed<=.25 else 0. self.move_seconds=self.move_seconds+dt if speed>=.8 else 0. if self.stop_seconds>=.4:self.stopped=True @@ -30,5 +31,5 @@ class MotionPresentation: target_open_mix=self.target,rendered_open_mix=self.dsp.mix,cutoff_hz=900., lift_ms=self.config.attack_ms,contain_ms=self.config.release_ms, stop_threshold_mps=.25,move_threshold_mps=.8,stop_dwell_seconds=.4,move_dwell_seconds=.15, - gain=1.,width=1.,added_delay_samples=0,unknown_policy='smooth bypass', + gain=1.,width=1.,negative_speed_tolerance_mps=.05,added_delay_samples=0,unknown_policy='smooth bypass', source='fresh current carState.vEgo; no future data')} diff --git a/roadscore/prototype/review_motion_presentation.py b/roadscore/prototype/review_motion_presentation.py index 73910d4041..69c49055af 100644 --- a/roadscore/prototype/review_motion_presentation.py +++ b/roadscore/prototype/review_motion_presentation.py @@ -34,7 +34,7 @@ def render(locked,out): before=time.perf_counter() y=dsp.process(pcm,speed=row.get('speed',0.),source_fresh=fresh,engagement_open_mix=open_mix) times.append(time.perf_counter()-before);dst.write(y) - states.append(dict(audio_s=start/rate,steering=row.get('steering'),speed=row.get('speed'),fresh=fresh,**dsp.snapshot()['motion_presentation'])) + states.append(dict(audio_s=start/rate,route_t=row.get('route_t'),source_age_seconds=block['callback_wall']-row.get('command_wall',block['callback_wall']),signal_fresh=block.get('signal_fresh'),steering=row.get('steering'),speed=row.get('speed'),fresh=fresh,**dsp.snapshot()['motion_presentation'])) transitions=[state for previous,state in zip(states,states[1:]) if previous['stopped'] and not state['stopped'] and state['fresh'] and state.get('speed',0)>=.8] event=transitions[0] if transitions else min(states,key=lambda x:x['rendered_open_mix']) start=max(0.,min(info.duration-45,event['audio_s']-15));end=min(info.duration,start+45) @@ -52,7 +52,7 @@ def render(locked,out): physical_bluetooth_latency='Not measured; these files compare musical processing, not speaker/video synchronization', settings=dsp.snapshot(),sample_frames=info.frames) (out/'report.json').write_text(json.dumps(report,indent=2));(out/'motion_states.json').write_text(json.dumps(states)) - (out/'index.html').write_text('''
Same accepted recording and same 45-second excerpt. B uses a strong 900 Hz low-pass while stopped and opens as the car starts moving. No regeneration, new melody, gain normalization or event samples.
Default remains off. This is a musical comparison, not Bluetooth/video synchronization. Existing engagement processing remains intact. This cannot isolate a lead instrument from a stereo mix.
''') + (out/'index.html').write_text('''Same accepted recording and same 45-second excerpt. B uses a strong 900 Hz low-pass while stopped and opens as the car starts moving. No regeneration, new melody, gain normalization or event samples.
Default remains off. This is a musical comparison, not Bluetooth/video synchronization. Existing engagement processing remains intact. This cannot isolate a lead instrument from a stereo mix.
''') return report if __name__=='__main__': diff --git a/roadscore/prototype/test_motion_presentation.py b/roadscore/prototype/test_motion_presentation.py index 962d1fa96a..15ed8b9c74 100644 --- a/roadscore/prototype/test_motion_presentation.py +++ b/roadscore/prototype/test_motion_presentation.py @@ -32,6 +32,18 @@ class MotionTests(unittest.TestCase): y=self.run_blocks(dsp,speed=float('nan'),source_fresh=False) self.assertTrue(np.array_equal(y,self.pcm));self.assertFalse(dsp.stopped) + def test_near_zero_signed_noise_does_not_reset_stop_dwell(self): + dsp=MotionPresentation(enabled=True) + for i in range(25): + y=dsp.process(self.pcm,speed=(-1 if i%2 else 1)*1e-25,source_fresh=True) + self.assertTrue(dsp.stopped);self.assertTrue(dsp.fresh) + self.assertLess(np.std(y)/np.std(self.pcm),.05) + self.assertTrue(np.array_equal(self.run_blocks(dsp,speed=1.,source_fresh=True),self.pcm)) + for invalid in (float('nan'),float('inf'),-.06): + y=self.run_blocks(dsp,speed=invalid,source_fresh=True) + self.assertFalse(dsp.fresh);self.assertFalse(dsp.stopped) + self.assertTrue(np.array_equal(y,self.pcm)) + def test_engagement_owns_inactive_presentation(self): dsp=MotionPresentation(enabled=True);eng=EngagementPresentation();config=PresentationConfig(enabled=True) y=self.run_blocks(dsp,speed=0.,source_fresh=True,engagement_open_mix=0.)