PT1 plant model#

  • IP-Core to model a PT1 plant

\[G(s)=\frac{K}{Ts +1}\]

With the gain \(K\) and time constant T.

  • Intended for HIL/SIL/xIL on the UltraZohm

  • PT1 is implemented in discrete time by using zero order hold transformation

  • Sample time of the integrator is \(T_s=\frac{1}{1\,MHz}\)

  • IP-Core clock frequency must be \(f_{clk}=100\,MHz\)!

  • IP-Core has single precision AXI ports

  • All calculations in the IP-Core are done in double precision!

  • Rationale: the machine epsilon for single precision is approximately \(\epsilon=6e-08\). The time discrete integrator multiplies the input with \(\frac{1}{T_s}\), resulting in small numbers. This results in noticable rounding errors for the integration compared to double precision. This effect als consistent between the IP-Core and Simulink, thus double precision is used in the IP-Core. AXI is 32-bit by default, thus the input and output values are converted to single precision.

IP-Core Hardware#

../../_images/uz_plantModel_pt1_top.svg

Fig. 328 Test bench of PT1 plant model IP-Core#

../../_images/uz_plantModel_pt1_inside.svg

Fig. 329 Implementation of plant model PT1 IP-Core#

  • The module takes all inputs and converts them from single precision to double precision.

  • The output is converted from double precision to single precision (using rounding to nearest value in both cases).

  • All input values are adjustable at run-time

  • The sample time is fixed!

  • The IP-Core uses Native Floating Point of the HDL-Coder

  • The time constant is written as its reciprocal to the AXI register to make the calculations on hardware simple (handled by the driver!)

  • The IP-Core uses an oversampling factor of 100

Example usage#

Vivado#

  • Add IP-Core to Vivado and connect to AXI (smartconnect)

  • Source IPCORE_CLK with a \(100\,MHz\) clock!

  • Connect other ports accordingly

  • Assign address to IP-Core

  • Build bitstream, export .xsa, update vitis platform

../../_images/uz_plant_model_vivado_example.png

Fig. 330 Example connection of IP-Core#

Vitis#

  • In a c-file that has xparameters.h included

  • Initialize the instance and configure it

struct uz_plantPT1_config_t config={
   .base_address=XPAR_UZ_PLANTMODEL_PT1_0_BASEADDR,
   .ip_core_frequency_Hz=100000000,
   .gain=1.0f,
   .time_constant=1.0f
};
uz_plantPT1_t* pt1=uz_plantPT1_init(config);
uz_plantPT1_set_input(pt1,0.0f);
  • Write the input and read the output of the block in the isr.c

  • Add a PI controller to control the PT1 (for example)

static float error_sum=0;
float output=uz_plantPT1_read_output(pt1);
float error=input-output;
error_sum+=error;
float K_p=0.3f;
float K_i=1.3f;
float pi_output=K_p*error+K_i*(1.0f/20000.0f)*error_sum; // 20000.0f is the sample rate of the ISR in this example
uz_plantPT1_set_input(pt1,pi_output);

Driver reference#

typedef struct uz_plantPT1_t uz_plantPT1_t#

Object definition of the plant model PT1 IP-Core.

struct uz_plantPT1_config_t#

Configuration struct for plant PT1 IP-Core.

Public Members

uint32_t base_address#

Base address of IP-Core instance

uint32_t ip_core_frequency_Hz#

Clock frequency of IP-Core

float gain#

Gain of PT1

float time_constant#

time constant of the PT1

uz_plantPT1_t *uz_plantPT1_init(struct uz_plantPT1_config_t config)#

Initialize an instance of the driver.

Parameters:
  • config – Configuration struct

Returns:

uz_plantPT1_t* Pointer to initialized instance of driver

void uz_plantPT1_reset_integrator(uz_plantPT1_t *self)#

Resets the integrator of the PT1 once.

Parameters:
  • self – Pointer to driver instance that is reset

void uz_plantPT1_set_input(uz_plantPT1_t *self, float input_value)#

Set the input value u(k) of the PT1.

Parameters:
  • self – Pointer to driver instance

  • input_value

void uz_plantPT1_set_gain(uz_plantPT1_t *self, float gain)#

Set the gain of the PT1.

Parameters:
  • self – Pointer to driver instance

  • gain

void uz_plantPT1_set_time_constant(uz_plantPT1_t *self, float time_constant)#

Set the time constant of the PT1.

Parameters:
  • self – Pointer to driver instance

  • time_constant

float uz_plantPT1_read_output(uz_plantPT1_t *self)#

Reads the output of the PT1.

Parameters:
  • self – Pointer to driver instance

Returns:

float