diff --git a/script-gen-manager/src/instr_metadata/mpsu50_metadata.rs b/script-gen-manager/src/instr_metadata/mpsu50_metadata.rs index 98773bf..afd2cca 100644 --- a/script-gen-manager/src/instr_metadata/mpsu50_metadata.rs +++ b/script-gen-manager/src/instr_metadata/mpsu50_metadata.rs @@ -27,6 +27,8 @@ impl Mpsu50Metadata { base.add_range("source.limiti".to_string(), 0.01, 5.1); + base.add_range("source.step_to_sweep_delay".to_string(), 0.0, 100.0); + // Add region maps // when pulse mode is off let exclude_i = NumberLimit::new(-10.0e-9, 10.0e-9, false, None); diff --git a/script-gen-manager/src/instr_metadata/msmu60_metadata.rs b/script-gen-manager/src/instr_metadata/msmu60_metadata.rs index 47b89cf..389dee9 100644 --- a/script-gen-manager/src/instr_metadata/msmu60_metadata.rs +++ b/script-gen-manager/src/instr_metadata/msmu60_metadata.rs @@ -46,6 +46,8 @@ impl Msmu60Metadata { base.add_range("source.limiti".to_string(), -1e-8, 1.515); base.add_range("source.limitv".to_string(), -0.02, 60.6); + base.add_range("source.step_to_sweep_delay".to_string(), 0.0, 100.0); + // Add region maps // when pulse mode is off let exclude_v = Some(NumberLimit::new(-0.01, 0.01, false, None)); diff --git a/script-gen-manager/src/model/sweep_data/parameters.rs b/script-gen-manager/src/model/sweep_data/parameters.rs index e2ebfac..005568d 100644 --- a/script-gen-manager/src/model/sweep_data/parameters.rs +++ b/script-gen-manager/src/model/sweep_data/parameters.rs @@ -50,6 +50,16 @@ impl ParameterFloat { unit, } } + + pub fn limit(&mut self, min: f64, max: f64) { + if self.value >= min && self.value <= max { + return; + } else if self.value < min { + self.value = min + } else { + self.value = max + } + } } impl ParameterString { diff --git a/script-gen-manager/src/model/sweep_data/sweep_config.rs b/script-gen-manager/src/model/sweep_data/sweep_config.rs index ca3a511..41761b7 100644 --- a/script-gen-manager/src/model/sweep_data/sweep_config.rs +++ b/script-gen-manager/src/model/sweep_data/sweep_config.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use crate::{ device::Device, + instr_metadata::{base_metadata::Metadata, enum_metadata::MetadataEnum}, model::{ chan_data::{ bias_channel::BiasChannel, step_channel::StepChannel, sweep_channel::SweepChannel, @@ -370,9 +371,27 @@ impl SweepConfig { .sweep_timing_config .measure_count .limit(1, 60000); + + // Validating Step to Sweep Delay + if !self.step_channels.is_empty() { + let device_metadata = self.step_channels[0] + .start_stop_channel + .common_chan_attributes + .device + .get_metadata(); + if let Some((min, max)) = + self.get_range_limits(&device_metadata, "source.step_to_sweep_delay") + { + self.step_global_parameters + .step_to_sweep_delay + .limit(min, max); + } + } + for bias_channel in &mut self.bias_channels { bias_channel.evaluate(); } + for step_channel in &mut self.step_channels { step_channel .start_stop_channel @@ -383,18 +402,6 @@ impl SweepConfig { .start_stop_channel .evaluate(self.sweep_global_parameters.sweep_points.value as usize); } - - // Check if only bias channels exist and display appropriate message - // if !self.bias_channels.is_empty() - // && self.step_channels.is_empty() - // && self.sweep_channels.is_empty() - // { - // self.status_msg = Some(StatusMsg::new( - // StatusType::Warning, - // String::from("Only bias channels are configured. Please add a step or sweep channel to generate a functional script."), - // )); - // println!("Warning: Only bias channels are configured. Please add a step or sweep channel to generate a functional script."); - // } } pub fn update_channel_devices(&mut self) { @@ -593,6 +600,14 @@ impl SweepConfig { } } + fn get_range_limits(&self, metadata: &MetadataEnum, key: &str) -> Option<(f64, f64)> { + match metadata { + MetadataEnum::Base(base_metadata) => base_metadata.get_range(key), + MetadataEnum::Msmu60(msmu60_metadata) => msmu60_metadata.get_range(key), + MetadataEnum::Mpsu50(mpsu50_metadata) => mpsu50_metadata.get_range(key), + } + } + pub fn reset(&mut self) { *self = SweepConfig::new(); } diff --git a/script-gen-ui/src/app/components/main-sweep/plot-container/plot-step/plot-step.component.ts b/script-gen-ui/src/app/components/main-sweep/plot-container/plot-step/plot-step.component.ts index 0d4d2f1..1278088 100644 --- a/script-gen-ui/src/app/components/main-sweep/plot-container/plot-step/plot-step.component.ts +++ b/script-gen-ui/src/app/components/main-sweep/plot-container/plot-step/plot-step.component.ts @@ -57,7 +57,7 @@ export class PlotStepComponent backgroundColor: '', color: '', }; - @Input() color = ''; + @Input() color = ''; private mutationObserver: MutationObserver | undefined; private originalBackgroundColor = ''; activeBackgroundColor = ''; @@ -95,6 +95,7 @@ export class PlotStepComponent size: 9, }, dtick: 1, + range: [0, 10], // tick0: 0, showtickprefix: 'none', showticksuffix: 'all', @@ -269,41 +270,88 @@ export class PlotStepComponent } private generatePlotData(yData: number[], type: string): void { - if (this.stepPoints) { + if (this.stepPoints && this.stepToSweepDelay) { + const delayTime = this.stepToSweepDelay?.value ?? 0; const targetLength = Math.max(2, Math.floor(this.plotWidth)); - let xData: number[] = []; + let processedYData = [...yData]; + let processedXData: number[] = []; + // Handle interpolation first if needed if (this.stepPoints.value > targetLength) { if (type == 'LIN') { - const interpolated = PlotUtils.linearInterpolation( - yData, - targetLength - ); - xData = interpolated.x; - yData = interpolated.y; + const interpolated = PlotUtils.linearInterpolation(processedYData, targetLength); + processedXData = interpolated.x; + processedYData = interpolated.y; } else if (type == 'LOG' || type == 'LIST') { - const interpolated = PlotUtils.minMaxInterpolation( - yData, - targetLength - ); - xData = interpolated.x; - yData = interpolated.y; + const interpolated = PlotUtils.minMaxInterpolation(processedYData, targetLength); + processedXData = interpolated.x; + processedYData = interpolated.y; } } else { - xData = Array.from({ length: this.stepPoints.value }, (_, i) => i) + processedXData = Array.from({ length: this.stepPoints.value }, (_, i) => i) .concat(this.stepPoints.value) .flat(); } - this.plotData1.x = xData; - this.plotData1.y = yData; - console.log('Plot data generated:', { - x: this.plotData1.x, - y: this.plotData1.y, - }); - this.plotLayout.xaxis.dtick = this.stepPoints.value / 10; + + if (delayTime > 0) { + const { x, y } = this.generateDataWithDelay(processedYData, processedXData, delayTime); + this.plotData1.x = x; + this.plotData1.y = y; + } else { + this.generateDataWithoutDelay(processedYData, processedXData); + } + + // console.log('Plot data generated:', { + // x: this.plotData1.x, + // y: this.plotData1.y, + // }); + // this.plotLayout.xaxis.dtick = (this.stepPoints.value + this.stepToSweepDelay?.value) / 10; + // Update x-axis range to include delay time for each step + // const delayTime = this.stepToSweepDelay?.value ?? 0; + const totalTime = this.stepPoints.value * (1 + delayTime); // Each step now takes (1 + delayTime) units + + this.plotLayout.xaxis.dtick = totalTime / 10; + this.plotLayout.xaxis.range = [0, totalTime]; } } + private generateDataWithDelay(yData: number[], xData: number[], delayTime: number): { x: number[], y: number[] } { + const finalX: number[] = []; + const finalY: number[] = []; + const delayPoints = Math.max(5, Math.floor(delayTime * 10)); + const numSteps = yData.length - 1; // Exclude the final repeated point + + // Generate data for each step with delay + for (let step = 0; step < numSteps; step++) { + const stepStartTime = step * (1 + delayTime); + const currentYValue = yData[step]; + + // Add delay period (repeat current y value) at the beginning of each step + for (let d = 0; d < delayPoints; d++) { + finalX.push(stepStartTime + (d * delayTime) / delayPoints); + finalY.push(currentYValue); + } + + // Add the actual step point after delay + finalX.push(stepStartTime + delayTime); + finalY.push(currentYValue); + } + + // Add final point + if (yData.length > 0) { + const finalStepTime = numSteps * (1 + delayTime); + finalX.push(finalStepTime); + finalY.push(yData[yData.length - 1]); + } + + return { x: finalX, y: finalY }; + } + + private generateDataWithoutDelay(yData: number[], xData: number[]): void { + this.plotData1.x = xData; + this.plotData1.y = yData; + } + private stepListPlot() { if (this.listStep && this.stepPoints && this.stop) { const stepValues = this.listStep diff --git a/script-gen-ui/src/app/components/main-sweep/plot-container/plot-sweep/plot-sweep.component.ts b/script-gen-ui/src/app/components/main-sweep/plot-container/plot-sweep/plot-sweep.component.ts index 8496c54..6115d48 100644 --- a/script-gen-ui/src/app/components/main-sweep/plot-container/plot-sweep/plot-sweep.component.ts +++ b/script-gen-ui/src/app/components/main-sweep/plot-container/plot-sweep/plot-sweep.component.ts @@ -76,6 +76,8 @@ export class PlotSweepComponent list = true; listSweep: ParameterFloat[] = []; numSteps: number | undefined; + stepToSweepDelay: ParameterFloat | undefined; + plotUtils = new PlotUtils(); plotLayout = { @@ -239,6 +241,7 @@ export class PlotSweepComponent this.numPoints = this.sweepGlobalParameters?.sweep_points; this.list = this.sweepGlobalParameters?.list_sweep; this.numSteps = this.stepGlobalParameters?.step_points.value; + this.stepToSweepDelay = this.stepGlobalParameters?.step_to_sweep_delay; // this.list = this.sweepGlobalParameters?.list_sweep; this.listSweep = this.sweepChannel.start_stop_channel.list; @@ -295,19 +298,76 @@ export class PlotSweepComponent if (this.numPoints && this.numSteps) { const numSteps = this.numSteps; const numberOfPoints = this.numPoints?.value; - this.plotData1.y = Array.from({ length: numSteps }, () => sweepValues) - .flat() - .concat(sweepValues[sweepValues.length - 1]); - - if (xData) { - this.plotData1.x = xData; + const delayTime = this.stepToSweepDelay?.value ?? 0; + + if (delayTime > 0) { + const { x, y } = this.generateDataWithDelay(sweepValues, numSteps, numberOfPoints, delayTime, xData); + this.plotData1.x = x; + this.plotData1.y = y; } else { - this.plotData1.x = Array.from({ length: numSteps }, (_, i) => - Array.from({ length: numberOfPoints }, (_, j) => i + j / numberOfPoints) - ) - .flat() - .concat(numSteps); + this.generateDataWithoutDelay(sweepValues, numSteps, numberOfPoints, xData); + } + } + } + + private generateDataWithDelay( + sweepValues: number[], + numSteps: number, + numberOfPoints: number, + delayTime: number, + xData?: number[] + ): { x: number[], y: number[] } { + const finalX: number[] = []; + const finalY: number[] = []; + const delayPoints = Math.max(5, Math.floor(delayTime * 10)); + + // Generate data for each step with delay + for (let step = 0; step < numSteps; step++) { + const stepStartTime = step * (1 + delayTime); + + // Add delay period (zeros) at the beginning of each step + for (let d = 0; d < delayPoints; d++) { + finalX.push(stepStartTime + (d * delayTime) / delayPoints); + finalY.push(0); } + + // Add the actual sweep data for this step + for (let j = 0; j < numberOfPoints; j++) { + if (xData) { + const originalIndex = step * numberOfPoints + j; + if (originalIndex < xData.length) { + finalX.push(stepStartTime + delayTime + (j / numberOfPoints)); + } + } else { + finalX.push(stepStartTime + delayTime + (j / numberOfPoints)); + } + finalY.push(sweepValues[j]); + } + } + + // Add final point + if (sweepValues.length > 0) { + const finalStepTime = numSteps * (1 + delayTime); + finalX.push(finalStepTime); + finalY.push(sweepValues[sweepValues.length - 1]); + } + + return { x: finalX, y: finalY }; + } + + private generateDataWithoutDelay(sweepValues: number[], numSteps: number, numberOfPoints: number, xData?: number[]) { + this.plotData1.y = Array.from({ length: numSteps }, () => sweepValues) + .flat() + .concat(sweepValues[sweepValues.length - 1]); + + if (xData) { + this.plotData1.x = xData; + } else { + this.plotData1.x = Array.from({ length: numSteps }, (_, i) => + Array.from({ length: numberOfPoints }, (_, j) => i + j / numberOfPoints) + ) + .flat() + .concat(numSteps); } } @@ -335,8 +395,13 @@ export class PlotSweepComponent } else { this.generatePlotDataxy(sweepValues); } - this.plotLayout.xaxis.dtick = this.numSteps / 10; - this.plotLayout.xaxis.range = [0, this.numSteps]; + + // Update x-axis range to include delay time for each step + const delayTime = this.stepToSweepDelay?.value ?? 0; + const totalTime = this.numSteps * (1 + delayTime); // Each step now takes (1 + delayTime) units + + this.plotLayout.xaxis.dtick = totalTime / 10; + this.plotLayout.xaxis.range = [0, totalTime]; } }