My global variables in my S-function builder don't seem updated properly whenever it runs.
조회 수: 3 (최근 30일)
이전 댓글 표시
Hi,
I'm running simulink with my "S-function builder" block, and it doesn't work as I expected at all.
< Function of my "S-function builder" block >
It generates a sinusoidal signal, "v_out" whose frequency "freq" is updated periodically according to the following 'if' sentence in my code below :
" if( (v_out >= 0) && (v_out_prev < 0) && (time >= freq_update_time + FreqTrackTime) ) "
When the frequency of "v_out" is updated, I want to minimize discontinuity in "v_out", so frequency is changed at the moment when "v_out" is changed from negative to positive (i.e., zero-crossing).
To notice the zero-crossing moment of "v_out", I used another global variable "v_out_prev", which is updated as "v_out_prev = v_out" at the end of my code, so it has the value of "v_out" one execution time before. So I added conditions for v_out >= 0 and v_out_prev < 0 in the 'if' sentence above.
< Problem of my "S-function builder" block >
As you can see from my Simulation Data Inspector capture below, the "v_out" is updated at some weird moment. I intended "v_out" is always updated when it zero-crosses from negative to positive, but sometimes it also changes when both my "v_out" and "v_out_prev" are positive.
Considering the condition for 'if' sentence, I couldn't understand its behavior.
So, I checked the values of "v_out" and "v_out_prev" outside and inside of the 'if" sentence with variables :
*voltage_out_s_func = v_out; // outside of if sentence
*v_out_prev_s_func = v_out_prev; // outside of if sentence
if( (v_out >= 0) && (v_out_prev < 0) && (time >= freq_update_time + FreqTrackTime) ){
*var_check_v_out = v_out; // inside of if sentence
*var_check_v_out_prev = v_out_prev; // inside of if sentence
When I check "v_out" and "v_out_prev" with Simulation Data Inspector, the values of "v_out" and "v_out_prev" are different when I compare inside and outside of the 'if' sentence.
*voltage_out_s_func = v_out; ==> 25.1 at t = 0.00009901 sec.
*v_out_prev_s_func = v_out_prev; ==> 17.9 at t = 0.00009901 sec.
*var_check_v_out = v_out; ==> 12.9 at t = 0.00009901 sec.
*var_check_v_out_prev = v_out_prev; ==> -10.3 at t = 0.00009901 sec.
My questions is how come those values are different? I think that makes unexpected update behavior of "v_out".
< Settings of my Simulink >
my "S-function builder" block sample mode was set as "continuous".
and the simulink model solver was set as "Fixed-step" with "auto" Solver, and "Fixed-step" size as 5e-9 sec.
/* Includes_BEGIN */
#include <math.h>
boolean_T volt_rising_prev;
real_T *phase_difference_buffer;
real_T PhaseDiffBufferAVG;
real_T theta_d_prev;
#define PhaseDiffBuffSize 10
#define FreqTrackTime 1e-6
#define FreqMax 4e6
#define FreqMin 2e6
volatile real_T v_out;
volatile real_T v_out_prev;
real_T freq;
real_T freq_update_time;
#define M_PI 3.141592
/* Includes_END */
/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */
void s_func_delay_test_Start_wrapper(SimStruct *S)
{
/* Start_BEGIN */
phase_difference_buffer = malloc(sizeof(real_T)*PhaseDiffBuffSize);
freq = 3.35e6;
/*
* Custom Start code goes here.
*/
/* Start_END */
}
void s_func_delay_test_Outputs_wrapper(const boolean_T *volt_rising,
const real_T *time_current_falling,
const real_T *time_voltage_falling,
const real_T *K_P,
const real_T *K_I,
const real_T *K_D,
real_T *voltage_out_s_func,
real_T *PhaseDiffBufferAVG_s_func,
real_T *freq_s_func,
real_T *time_s_func,
real_T *freq_update_time_s_func,
real_T *v_out_prev_s_func,
real_T *loop_check,
real_T *loop_check_2,
real_T *var_check_v_out,
real_T *var_check_v_out_prev,
SimStruct *S)
{
real_T time = ssGetT(S);
v_out = 300*sin(2*M_PI*freq*(time - freq_update_time));
*loop_check_2 = *loop_check_2 + 1;
if (ssIsMajorTimeStep(S)){
if( *volt_rising == true && volt_rising_prev == false ){
PhaseDiffBufferAVG = 0;
for(int i = 0; i < PhaseDiffBuffSize; i++){
*(phase_difference_buffer + i) = *(phase_difference_buffer + i + 1);
if(i == PhaseDiffBuffSize - 1){
*(phase_difference_buffer + i) = *time_current_falling - *time_voltage_falling;
}
PhaseDiffBufferAVG = PhaseDiffBufferAVG + *(phase_difference_buffer + i)/PhaseDiffBuffSize;
*PhaseDiffBufferAVG_s_func = PhaseDiffBufferAVG;
}
}
volt_rising_prev = *volt_rising;
}
*voltage_out_s_func = v_out;
*v_out_prev_s_func = v_out_prev;
if( (v_out >= 0) && (v_out_prev < 0) && (time >= freq_update_time + FreqTrackTime) ){
*loop_check = *loop_check + 1;
*var_check_v_out = v_out;
*var_check_v_out_prev = v_out_prev;
real_T theta_d_curr = 2 * M_PI * PhaseDiffBufferAVG * freq;
freq = *K_P * freq * theta_d_curr + *K_I * freq + *K_D * (theta_d_curr - theta_d_prev)/(FreqTrackTime);
if (freq >= FreqMax){
freq = FreqMax;
}else if (freq <= FreqMin){
freq = FreqMin;
}
theta_d_prev = theta_d_curr;
freq_update_time = ssGetT(S);
*freq_update_time_s_func = freq_update_time;
}
v_out_prev = v_out;
*freq_s_func = freq;
*time_s_func = time;
}
void s_func_delay_test_Terminate_wrapper(SimStruct *S)
{
/* Terminate_BEGIN */
/*
* Custom Terminate code goes here.
*/
/* Terminate_END */
}



댓글 수: 0
채택된 답변
Debadipto
2025년 1월 3일
I believe the main reason why you're observing the discrepancy is that in Simulink's continuous sample mode S-function can be evaluated multiple times within a single time step, leading to changes in variable values between these evaluations. This is crucial for zero-crossing detection. Here's my understanding of the situation:
Since your block operates in continuous mode, Simulink calls the Outputs function several times within each time step to:
1. Detect state events such as zero crossings
2. Compute intermediate points for the solver
3. Evaluate the final outputs
The problem likely arises from how "v_out" and "v_out_prev" are updated during these evaluations. The discrepancy in values inside and outside the if statement occurs because:
1. The function might be invoked multiple times at the same time point.
2. "v_out_prev" is updated at the end of each function call with "v_out_prev = v_out".
3. As a result, "v_out_prev" may change between evaluations within the same time step.
To address this, consider:
1. Introducing a "zero_crossing_detected" flag to prevent multiple detections within the same zero-crossing event.
2. Using "ode23t" or "ode15s" solvers instead of "auto," as they handle zero-crossings more effectively.
댓글 수: 0
추가 답변 (0개)
참고 항목
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!