// Automatically generated C++ file on Tue Dec 9 17:14:01 2025 // // To build with Digital Mars C++ Compiler: // // dmc -mn -WD dab_outerloop.cpp kernel32.lib #include extern "C" __declspec(dllexport) void (*bzero)(void *ptr, unsigned int count) = 0; union uData { bool b; char c; unsigned char uc; short s; unsigned short us; int i; unsigned int ui; float f; double d; long long int i64; unsigned long long int ui64; char *str; unsigned char *bytes; }; // int DllMain() must exist and return 1 for a process to load the .DLL // See https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain for more information. int __stdcall DllMain(void *module, unsigned int reason, void *reserved) { return 1; } // #undef pin names lest they collide with names in any header file(s) you might include. #undef Vout #undef Vo_ref #undef clk #undef P_ref // ----------------------------------------------------------------------------- // Tunable PI gains and power limits (edit these as needed) // ----------------------------------------------------------------------------- static const double Kp_v = 200.0; // [W/V] proportional gain static const double Ki_v = 5000.0; // [W/(V*s)] integral gain static const double P_MAX = 50000.0; // [W] saturation (ąP_MAX) // ----------------------------------------------------------------------------- // Per-instance state // ----------------------------------------------------------------------------- struct sDAB_OUTERLOOP { bool clk_prev; // last clock level for edge detection bool first_sample; // first valid sample flag double last_t; // time of last control update double integ; // integrator state [W] double P_last; // last output command [W] }; extern "C" __declspec(dllexport) void dab_outerloop(struct sDAB_OUTERLOOP **opaque, double t, union uData *data) { double Vout = data[0].d; // input double Vo_ref = data[1].d; // input double clk = data[2].d; // input double &P_ref = data[3].d; // output if(!*opaque) { *opaque = (struct sDAB_OUTERLOOP *) malloc(sizeof(struct sDAB_OUTERLOOP)); bzero(*opaque, sizeof(struct sDAB_OUTERLOOP)); (*opaque)->clk_prev = false; (*opaque)->first_sample = true; (*opaque)->last_t = 0.0; (*opaque)->integ = 0.0; (*opaque)->P_last = 0.0; } struct sDAB_OUTERLOOP *inst = *opaque; // Implement module evaluation code here: // -------------------------------------------------------------------------- // 1) Edge detect on clk: update only on rising edge // -------------------------------------------------------------------------- bool clk_now = (clk > 0.5); // simple logic threshold bool rising = clk_now && !inst->clk_prev; // detect rising edge inst->clk_prev = clk_now; if (!rising) { // No new sample: hold last P_ref P_ref = inst->P_last; return; } // -------------------------------------------------------------------------- // 2) Compute sample time Ts from simulation time // -------------------------------------------------------------------------- double Ts; if (inst->first_sample) { Ts = 1e-4; // fallback Ts (~10 kHz), not critical inst->first_sample = false; } else { Ts = t - inst->last_t; if (Ts <= 0.0) Ts = 1e-6; // guard against weird timestamps } inst->last_t = t; // -------------------------------------------------------------------------- // 3) Voltage PI controller: e = Vo_ref - Vout ? P_ref (watts) // -------------------------------------------------------------------------- double error = Vo_ref - Vout; // [V] // Proportional term double P_p = Kp_v * error; // [W] // Integral term (simple integration; you can add anti-windup later) inst->integ += Ki_v * Ts * error; // [W] double P_cmd = P_p + inst->integ; // unsaturated command [W] // Saturate to ąP_MAX if (P_cmd > P_MAX) P_cmd = P_MAX; if (P_cmd < -P_MAX) P_cmd = -P_MAX; // -------------------------------------------------------------------------- // 4) Output and store state // -------------------------------------------------------------------------- P_ref = P_cmd; inst->P_last = P_cmd; } extern "C" __declspec(dllexport) void Destroy(struct sDAB_OUTERLOOP *inst) { free(inst); }