/**************************************************************************** * libs/libdsp/lib_foc.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: foc_current_controller * * Description: * This function implements FOC current controller algorithm. * * Input Parameters: * foc - (in/out) pointer to the FOC data * v_dq_req - (in) pointer to the voltage DQ request frame * * Returned Value: * None * ****************************************************************************/ static void foc_current_controller(FAR struct foc_data_f32_s *foc, FAR dq_frame_f32_t *v_dq_req) { FAR pid_controller_f32_t *id_pid = &foc->id_pid; FAR pid_controller_f32_t *iq_pid = &foc->iq_pid; LIBDSP_DEBUGASSERT(foc != NULL); LIBDSP_DEBUGASSERT(v_dq_req != NULL); /* Get dq current error */ foc->i_dq_err.d = foc->i_dq_ref.d - foc->i_dq.d; foc->i_dq_err.q = foc->i_dq_ref.q - foc->i_dq.q; /* NOTE: PI controllers saturation is updated in foc_vdq_mag_max_set() */ /* PI controller for d-current (flux loop) */ v_dq_req->d = pi_controller(id_pid, foc->i_dq_err.d); /* PI controller for q-current (torque loop) */ v_dq_req->q = pi_controller(iq_pid, foc->i_dq_err.q); } /**************************************************************************** * Name: foc_vab_mod_scale_set * * Description: * * Input Parameters: * foc - (in/out) pointer to the FOC data * scale - (in) scaling factor for alpha-beta voltage * * Returned Value: * None * ****************************************************************************/ static void foc_vab_mod_scale_set(FAR struct foc_data_f32_s *foc, float scale) { LIBDSP_DEBUGASSERT(foc != NULL); foc->vab_mod_scale = scale; } /**************************************************************************** * Name: foc_vdq_mag_max_set * * Description: * Set maximum dq voltage vector magnitude * * Input Parameters: * foc - (in/out) pointer to the FOC data * max - (in) maximum dq voltage magnitude * * Returned Value: * None * ****************************************************************************/ static void foc_vdq_mag_max_set(FAR struct foc_data_f32_s *foc, float max) { LIBDSP_DEBUGASSERT(foc != NULL); foc->vdq_mag_max = max; /* Update regulators saturation */ pi_saturation_set(&foc->id_pid, -foc->vdq_mag_max, foc->vdq_mag_max); pi_saturation_set(&foc->iq_pid, -foc->vdq_mag_max, foc->vdq_mag_max); } /**************************************************************************** * Name: foc_vdq_ref_set * * Description: * Set dq requested voltage vector * * Input Parameters: * foc - (in/out) pointer to the FOC data * vdq_ref - (in) pointer to the requested idq voltage * * Returned Value: * None * ****************************************************************************/ static void foc_vdq_ref_set(FAR struct foc_data_f32_s *foc, FAR dq_frame_f32_t *vdq_ref) { LIBDSP_DEBUGASSERT(foc != NULL); LIBDSP_DEBUGASSERT(vdq_ref != NULL); foc->v_dq.d = vdq_ref->d; foc->v_dq.q = vdq_ref->q; } /**************************************************************************** * Name: foc_idq_ref_set * * Description: * Set dq reference current vector * * Input Parameters: * foc - (in/out) pointer to the FOC data * idq_ref - (in) pointer to the reference idq current * * Returned Value: * None * ****************************************************************************/ static void foc_idq_ref_set(FAR struct foc_data_f32_s *foc, FAR dq_frame_f32_t *idq_ref) { LIBDSP_DEBUGASSERT(foc != NULL); LIBDSP_DEBUGASSERT(idq_ref != NULL); foc->i_dq_ref.d = idq_ref->d; foc->i_dq_ref.q = idq_ref->q; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: foc_init * * Description: * Initialize FOC controller * * Input Parameters: * foc - (in/out) pointer to the FOC data * init - (in) pointer to the FOC initialization data * * Returned Value: * None * ****************************************************************************/ void foc_init(FAR struct foc_data_f32_s *foc, FAR struct foc_initdata_f32_s *init) { /* Reset data */ memset(foc, 0, sizeof(struct foc_data_f32_s)); /* Initialize PI current d component */ pi_controller_init(&foc->id_pid, init->id_kp, init->id_ki); /* Initialize PI current q component */ pi_controller_init(&foc->iq_pid, init->iq_kp, init->iq_ki); /* Disable PI intergral part reset when saturated */ pi_ireset_enable(&foc->iq_pid, false); pi_ireset_enable(&foc->id_pid, false); /* Enable PI anti-windup protection */ pi_antiwindup_enable(&foc->iq_pid, 0.99, true); pi_antiwindup_enable(&foc->id_pid, 0.99, true); } /**************************************************************************** * Name: foc_vbase_update * * Description: * Update base voltage for FOC controller * * Input Parameters: * foc - (in/out) pointer to the FOC data * vbase - (in) base voltage for FOC * * Returned Value: * None * ****************************************************************************/ void foc_vbase_update(FAR struct foc_data_f32_s *foc, float vbase) { float scale = 0.0f; float mag_max = 0.0f; /* Prevent division by zero */ if (vbase < 1e-10f) { vbase = 1e-10f; } /* NOTE: this is base voltage for FOC, not bus voltage! */ scale = (1.0f / vbase); mag_max = vbase; /* Update */ foc_vab_mod_scale_set(foc, scale); foc_vdq_mag_max_set(foc, mag_max); } /**************************************************************************** * Name: foc_angle_update * * Description: * Update FOC data with new motor phase angle. * * Input Parameters: * foc - (in/out) pointer to the FOC data * angle - (in) pointer to the phase angle data * * Returned Value: * None * ****************************************************************************/ void foc_angle_update(FAR struct foc_data_f32_s *foc, FAR phase_angle_f32_t *angle) { LIBDSP_DEBUGASSERT(foc != NULL); LIBDSP_DEBUGASSERT(angle != NULL); /* Copy angle to foc data */ foc->angle.angle = angle->angle; foc->angle.sin = angle->sin; foc->angle.cos = angle->cos; } /**************************************************************************** * Name: foc_iabc_update * * Description: * Update FOC data with new iabc frame. * * To work properly this function requires some additional steps: * 1. phase angle must be set with foc_angle_update() * * Input Parameters: * foc - (in/out) pointer to the FOC data * i_abc - (in) pointer to the ABC current frame * * Returned Value: * None * ****************************************************************************/ void foc_iabc_update(FAR struct foc_data_f32_s *foc, FAR abc_frame_f32_t *i_abc) { dq_frame_f32_t i_dq; LIBDSP_DEBUGASSERT(foc != NULL); LIBDSP_DEBUGASSERT(i_abc != NULL); /* Reset data */ i_dq.d = 0; i_dq.q = 0; /* Copy ABC current to foc data */ foc->i_abc.a = i_abc->a; foc->i_abc.b = i_abc->b; foc->i_abc.c = i_abc->c; /* Convert abc current to alpha-beta current */ clarke_transform(&foc->i_abc, &foc->i_ab); /* Convert alpha-beta current to dq current */ park_transform(&foc->angle, &foc->i_ab, &i_dq); /* Store dq current */ foc->i_dq.d = i_dq.d; foc->i_dq.q = i_dq.q; } /**************************************************************************** * Name: foc_voltage_control * * Description: * Process FOC voltage control. * * Input Parameters: * foc - (in/out) pointer to the FOC data * vdq_ref - (in) voltage dq reference frame * * Returned Value: * None * ****************************************************************************/ void foc_voltage_control(FAR struct foc_data_f32_s *foc, FAR dq_frame_f32_t *vdq_ref) { LIBDSP_DEBUGASSERT(foc != NULL); /* Update VDQ request */ foc_vdq_ref_set(foc, vdq_ref); /* Inverse Park transform (voltage dq -> voltage alpha-beta) */ inv_park_transform(&foc->angle, &foc->v_dq, &foc->v_ab); #ifdef CONFIG_LIBDSP_FOC_VABC /* Inverse Clarke transform (voltage alpha-beta -> voltage abc) */ inv_clarke_transform(&foc->v_ab, &foc->v_abc); #endif /* Normalize the alpha-beta voltage to get the alpha-beta modulation * voltage */ foc->v_ab_mod.a = foc->v_ab.a * foc->vab_mod_scale; foc->v_ab_mod.b = foc->v_ab.b * foc->vab_mod_scale; } /**************************************************************************** * Name: foc_current_control * * Description: * Process FOC current control. * * Input Parameters: * foc - (in/out) pointer to the FOC data * idq_ref - (in) current dq reference frame * vdq_comp - (in) voltage dq compensation frame * vdq_ref - (out) voltage dq reference frame * * Returned Value: * None * * TODO: add some reference and a brief description of the FOC * ****************************************************************************/ void foc_current_control(FAR struct foc_data_f32_s *foc, FAR dq_frame_f32_t *idq_ref, FAR dq_frame_f32_t *vdq_comp, FAR dq_frame_f32_t *vdq_ref) { LIBDSP_DEBUGASSERT(foc != NULL); /* Update IDQ reference */ foc_idq_ref_set(foc, idq_ref); /* Run FOC current controller (current dq -> voltage dq) */ foc_current_controller(foc, vdq_ref); /* DQ voltage compensation */ vdq_ref->d = vdq_ref->d - vdq_comp->d; vdq_ref->q = vdq_ref->q - vdq_comp->q; } /**************************************************************************** * Name: foc_vabmod_get * * Description: * Get result from the FOC controller (foc_current_control or * foc_voltage_control) * * Input Parameters: * foc - (in/out) pointer to the FOC data * v_ab_mod - (out) pointer to the voltage alpha-beta modulation frame * * Returned Value: * None * ****************************************************************************/ void foc_vabmod_get(FAR struct foc_data_f32_s *foc, FAR ab_frame_f32_t *v_ab_mod) { LIBDSP_DEBUGASSERT(foc != NULL); LIBDSP_DEBUGASSERT(v_ab_mod != NULL); v_ab_mod->a = foc->v_ab_mod.a; v_ab_mod->b = foc->v_ab_mod.b; } /**************************************************************************** * Name: foc_vdq_mag_max_get * * Description: * Get maximum dq voltage vector magnitude * * Input Parameters: * foc - (in/out) pointer to the FOC data * max - (out) maximum dq voltage magnitude * * Returned Value: * None * ****************************************************************************/ void foc_vdq_mag_max_get(FAR struct foc_data_f32_s *foc, FAR float *max) { LIBDSP_DEBUGASSERT(foc != NULL); *max = foc->vdq_mag_max; }