Power System Platform  2026w23a-beta
Loading...
Searching...
No Matches
PSPModel.cpp
1#include <stdio.h>
2#include <cmath>
3#include <string.h>
4#include <windows.h>
5#include <stdint.h>
6
8{
9public:
10
11 PhasorEstimator(double sampleRate = 1e6, double notchRadius = 0.5) : Fs(sampleRate), r(notchRadius)
12 {
13 Reset();
14 UpdateFrequency(60.0);
15 }
16
17 void Reset()
18 {
19 x1Id = x2Id = 0.0;
20 y1Id = y2Id = 0.0;
21
22 x1Iq = x2Iq = 0.0;
23 y1Iq = y2Iq = 0.0;
24
25 Id = 0.0;
26 Iq = 0.0;
27
28 lastFreq = -1.0;
29 }
30
31 void UpdateFrequency(double freq)
32 {
33 if(std::abs(freq-lastFreq) < 1e-9)
34 return;
35
36 lastFreq = freq;
37
38 double w0 = 2.0*M_PI*(2.0*freq)/Fs;
39
40 double c = cos(w0);
41
42 double bb0 = 1.0;
43 double bb1 = -2.0*c;
44 double bb2 = 1.0;
45
46 a1 = -2.0*r*c;
47 a2 = r*r;
48
49 double gain =
50 (1.0+a1+a2)/
51 (bb0+bb1+bb2);
52
53 b0 = gain*bb0;
54 b1 = gain*bb1;
55 b2 = gain*bb2;
56 }
57
58 void Update(double current,
59 double phase,
60 double freq)
61 {
62 UpdateFrequency(freq);
63
64 double s = sin(phase);
65 double c = cos(phase);
66
67 double IdRaw = current*s;
68 double IqRaw = current*c;
69
70 //-----------------------------------
71 // Id
72 //-----------------------------------
73
74 Id = b0*IdRaw + b1*x1Id + b2*x2Id - a1*y1Id - a2*y2Id;
75
76 x2Id = x1Id;
77 x1Id = IdRaw;
78
79 y2Id = y1Id;
80 y1Id = Id;
81
82 //-----------------------------------
83 // Iq
84 //-----------------------------------
85
86 Iq = b0*IqRaw + b1*x1Iq + b2*x2Iq - a1*y1Iq - a2*y2Iq;
87
88 x2Iq = x1Iq;
89 x1Iq = IqRaw;
90
91 y2Iq = y1Iq;
92 y1Iq = Iq;
93 }
94
95 double GetId() const
96 {
97 return sqrt(2.0)*Id;
98 }
99
100 double GetIq() const
101 {
102 return sqrt(2.0)*Iq;
103 }
104
105 double GetMagnitude() const
106 {
107 double ir = GetId();
108 double ii = GetIq();
109
110 return sqrt(ir*ir+ii*ii);
111 }
112
113 double GetAngle() const
114 {
115 return atan2(GetIq(),GetId());
116 }
117
118private:
119
120 double Fs;
121 double r;
122
123 double lastFreq;
124
125 double b0,b1,b2;
126 double a1,a2;
127
128 //-----------------------------
129 // Id
130 //-----------------------------
131
132 double x1Id,x2Id;
133 double y1Id,y2Id;
134
135 //-----------------------------
136 // Iq
137 //-----------------------------
138
139 double x1Iq,x2Iq;
140 double y1Iq,y2Iq;
141
142 //-----------------------------
143
144 double Id;
145 double Iq;
146};
147
148enum Mode
149{
150 RAW_CURRENT = 0,
151 PHASOR = 1,
152 BOTH = 2
153};
154
155struct Sample
156{
157 double current[3];
158};
159
160struct Phasor
161{
162 double Id[3];
163 double Iq[3];
164};
165
166// Shared memory structure used for data exchange between PSP and ATP.
168{
169 uint32_t nPh; // Number of phases
170
171 double t; // Current simulation time
172
173 double vrms; // RMS voltage at the PSP bus
174 double freq; // System frequency at the PSP bus
175 double theta; // Voltage phase angle at the PSP bus
176 double phase; // Continuous reference angle
177
178 double stoptime; // ATP simulation end time
179 double atpStepsize; // ATP steptime
180 double pspStepsize; // PSP steptime
181
182 Mode mode; // Data acquisition mode
183 int terminate; // Simulation termination flag
184
185 Phasor phasor; // Quadrature phasor components
186
187 uint32_t stepCount; // ATP steps since last synchronization
188 uint32_t syncSteps; // ATP steps between synchronizations
189
190 Sample samples[]; // Current samples collected between synchronizations
191};
192
193HANDLE hPSPReady = NULL;
194HANDLE hATPReady = NULL;
195HANDLE hMapFile = NULL;
196SharedData* data = NULL;
197
198const double PHASE_A = 0.0;
199const double PHASE_B = -2.0 * M_PI / 3.0;
200const double PHASE_C = 2.0 * M_PI / 3.0;
201
202static PhasorEstimator estimator[3];
203
204const double phaseShift[3] =
205{
206 PHASE_A,
207 PHASE_B,
208 PHASE_C
209};
210
211inline void SaveCurrent(const double current[])
212{
213 if(data->stepCount >= data->syncSteps)
214 {
215 printf("Current buffer full!\n");
216 return;
217 }
218
219 for(int i = 0; i < data->nPh; ++i)
220 data->samples[data->stepCount].current[i] = current[i];
221}
222
223inline void UpdatePhasor(const double current[])
224{
225 for(int i = 0; i < data->nPh; ++i)
226 {
227 estimator[i].Update(
228 current[i],
229 data->phase,
230 data->freq);
231
232 data->phasor.Id[i] = estimator[i].GetId();
233 data->phasor.Iq[i] = estimator[i].GetIq();
234 }
235}
236
237inline bool ProcessSharedData(const double current[])
238{
239 switch(data->mode)
240 {
241 case RAW_CURRENT:
242 SaveCurrent(current);
243 break;
244
245 case PHASOR:
246 UpdatePhasor(current);
247 break;
248
249 case BOTH:
250 SaveCurrent(current);
251 UpdatePhasor(current);
252 break;
253
254 default:
255 printf("Invalid acquisition mode.\n");
256 return false;
257 }
258
259 data->stepCount++;
260
261 if(data->stepCount < data->syncSteps) // Not yet the time to synchronize with PSP
262 return false;
263
264 return true; // Synchronize with PSP
265}
266
267extern "C"
268void psp_model_m__(double xdata_ar[], double xin_ar[], double xout_ar[], double xvar_ar[])
269{
270 if(data == NULL)
271 {
272 printf("Shared memory not initialized.\n");
273 return;
274 }
275 //static int step = 0;
276 //step++;
277
278 data->nPh = xdata_ar[0];
279 data->stoptime = xdata_ar[1];
280 data->atpStepsize = xdata_ar[2];
281
282 double vth[3];
283 double rth[3];
284 for(int i = 0; i < data->nPh; ++i) {
285 vth[i] = xin_ar[i];
286 rth[i] = xin_ar[i + data->nPh];
287 }
288 data->t = xin_ar[2* data->nPh];
289
290 double phase = xvar_ar[0];
291 double lastTime = xvar_ar[1];
292
293 double dt = data->t - lastTime;
294
295 if(dt > 0)
296 {
297 phase += 2*M_PI*data->freq*dt;
298 phase = fmod(phase, 2.0*M_PI);
299 lastTime = data->t;
300 }
301
302 xvar_ar[0] = phase;
303 xvar_ar[1] = lastTime;
304
305 data->phase = phase;
306
307 if (data->t >= data->stoptime - 1e-12) data->terminate = 1;
308 else data->terminate = -1;
309
310 double v[3];
311 for (int i = 0; i < data->nPh; ++i )
312 v[i] = data->vrms * sqrt(2.0) * sin(data->phase + data->theta + phaseShift[i]);
313
314 double current[3] = {0.0, 0.0, 0.0};
315 for(int i = 0; i < data->nPh; ++i) {
316 if(fabs(rth[i]) > 1e-12)
317 current[i] = (vth[i]-v[i])/rth[i];
318 xout_ar[i] = current[i];
319 }
320
321 if(ProcessSharedData(current))
322 {
323 if(!SetEvent(hATPReady))
324 {
325 printf("Error in SetEvent ATP: %lu\n", GetLastError());
326 }
327
328 DWORD ret = WaitForSingleObject(hPSPReady, INFINITE);
329
330 if(ret == WAIT_OBJECT_0)
331 {
332 printf("Event received!\n");
333 }
334 else
335 {
336 printf("Error in WaitForSingleObject: %lu\n", GetLastError());
337 }
338
339 data->stepCount = 0;
340 }
341 return;
342}
343
344extern "C"
345void psp_model_i__(double xdata_ar[], double xin_ar[], double xout_ar[], double xvar_ar[])
346{
347 printf("Initializing model 'PSP MODEL'.\n");
348
349 hPSPReady = CreateEventW(
350 NULL,
351 FALSE, // auto-reset
352 FALSE, // inicialmente não sinalizado
353 L"PSPBridge_PSPReady");
354
355 if(hPSPReady == NULL)
356 {
357 printf("Error in CreateEvent: %lu\n", GetLastError());
358 }
359
360 hATPReady = CreateEventW(
361 NULL,
362 FALSE,
363 FALSE,
364 L"PSPBridge_ATPReady");
365
366 if(hATPReady == NULL)
367 {
368 printf("Error in CreateEvent: %lu\n", GetLastError());
369 }
370
371 if(!SetEvent(hATPReady))
372 {
373 printf("Error in SetEvent ATP: %lu\n", GetLastError());
374 }
375
376 double pspStepsize = xdata_ar[3];
377 double atpStepsize = xdata_ar[2];
378
379 const uint32_t syncSteps = static_cast<uint32_t>(std::ceil(pspStepsize / atpStepsize - 1e-12));
380
381 size_t bytes =
382 sizeof(SharedData)
383 + syncSteps * sizeof(Sample);
384
385 hMapFile = CreateFileMappingW(
386 INVALID_HANDLE_VALUE,
387 NULL,
388 PAGE_READWRITE,
389 0,
390 bytes,
391 L"PSPBridgeSharedMemory");
392
393 if(hMapFile == NULL)
394 {
395 printf("Error in CreateFileMapping: %lu\n", GetLastError());
396 return;
397 }
398
399 data = (SharedData*)MapViewOfFile(
400 hMapFile,
401 FILE_MAP_ALL_ACCESS,
402 0,
403 0,
404 bytes);
405
406 if(data == NULL)
407 {
408 printf("Error in MapViewOfFile: %lu\n", GetLastError());
409 CloseHandle(hMapFile);
410 return;
411 }
412
413 for(int i = 0; i < 3; ++i)
414 estimator[i].Reset();
415
416
417 memset(data, 0 , bytes);
418 data->nPh = xdata_ar[0];
419 data->stoptime = xdata_ar[1];
420 data->vrms = 0.0;
421 data->freq = 0.0;
422 data->mode = PHASOR;
423 data->terminate = -1;
424 data->syncSteps = syncSteps;
425 data->stepCount = 0;
426
427 xvar_ar[0] = 0.0;
428 xvar_ar[1] = 0.0;
429
430 printf("Waiting PSP to initialize...\n");
431
432 DWORD ret = WaitForSingleObject(hPSPReady, INFINITE);
433
434 if(ret != WAIT_OBJECT_0)
435 {
436 printf("Error waiting PSP.\n");
437 return;
438 }
439
440 return;
441}