My global variables in my S-function builder don't seem updated properly whenever it runs.

4 次查看(过去 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 */
}

采纳的回答

Debadipto
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 个)

类别

Help CenterFile Exchange 中查找有关 Naming Conventions 的更多信息

产品


版本

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by