/* Use quick charge if specified. */ double DSD_555_ASTBL_T_RC_CHARGE(discrete_555_desc info) { return((DSD_555_ASTBL__R1 + (((info.options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) != 0) ? 0 : DSD_555_ASTBL__R2)) * DSD_555_ASTBL__C); }
//DISCRETE_CLASS_DESTRUCTOR(_name) \ //~discrete_dsd_555_astbl_node() { } // discrete_base_node //DISCRETE_RESET(dsd_555_astbl) public override void reset() { discrete_555_desc info = (discrete_555_desc)this.custom_data(); //DISCRETE_DECLARE_INFO(discrete_555_desc) m_use_ctrlv = (this.input_is_node() >> 4) & 1; m_output_type = info.options & DISC_555_OUT_MASK; /* Use the defaults or supplied values. */ m_v_out_high = (info.v_out_high == DEFAULT_555_HIGH) ? info.v_pos - 1.2 : info.v_out_high; /* setup v_charge or node */ m_v_charge_node = m_device.node_output_ptr((int)info.v_charge); if (m_v_charge_node == null) { m_v_charge = (info.v_charge == DEFAULT_555_CHARGE) ? info.v_pos : info.v_charge; if ((info.options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) != 0) { m_v_charge -= 0.5; } } if ((DSD_555_ASTBL__CTRLV != -1) && m_use_ctrlv == 0) { /* Setup based on supplied Control Voltage static value */ m_threshold = DSD_555_ASTBL__CTRLV; m_trigger = DSD_555_ASTBL__CTRLV / 2.0; } else { /* Setup based on v_pos power source */ m_threshold = info.v_pos * 2.0 / 3.0; m_trigger = info.v_pos / 3.0; } /* optimization if none of the values are nodes */ m_has_rc_nodes = 0; if ((this.input_is_node() & DSD_555_ASTBL_RC_MASK) != 0) { m_has_rc_nodes = 1; } else { m_t_rc_bleed = DSD_555_ASTBL_T_RC_BLEED; m_exp_bleed = RC_CHARGE_EXP(m_t_rc_bleed); m_t_rc_charge = DSD_555_ASTBL_T_RC_CHARGE(info); m_exp_charge = RC_CHARGE_EXP(m_t_rc_charge); m_t_rc_discharge = DSD_555_ASTBL_T_RC_DISCHARGE; m_exp_discharge = RC_CHARGE_EXP(m_t_rc_discharge); } m_output_is_ac = info.options & DISC_555_OUT_AC; /* Calculate DC shift needed to make squarewave waveform AC */ m_ac_shift = (m_output_is_ac != 0) ? -m_v_out_high / 2.0 : 0; m_flip_flop = 1; m_cap_voltage = 0; /* Step to set the output */ this.step(); }
//DISCRETE_STEP(dsd_555_astbl) public void step() { discrete_555_desc info = (discrete_555_desc)this.custom_data(); //DISCRETE_DECLARE_INFO(discrete_555_desc) int count_f = 0; int count_r = 0; double dt; /* change in time */ double x_time = 0; /* time since change happened */ double v_cap = m_cap_voltage; /* Current voltage on capacitor, before dt */ double v_cap_next = 0; /* Voltage on capacitor, after dt */ double v_charge, exponent = 0; uint8_t flip_flop = (uint8_t)m_flip_flop; uint8_t update_exponent = 0; double v_out = 0.0; /* put commonly used stuff in local variables for speed */ double threshold = m_threshold; double trigger = m_trigger; if (DSD_555_ASTBL__RESET) { /* We are in RESET */ set_output(0, 0); m_flip_flop = 1; m_cap_voltage = 0; return; } /* Check: if the Control Voltage node is connected. */ if (m_use_ctrlv != 0) { /* If CV is less then .25V, the circuit will oscillate way out of range. * So we will just ignore it when it happens. */ if (DSD_555_ASTBL__CTRLV < .25) { return; } /* If it is a node then calculate thresholds based on Control Voltage */ threshold = DSD_555_ASTBL__CTRLV; trigger = DSD_555_ASTBL__CTRLV / 2.0; /* Since the thresholds may have changed we need to update the FF */ if (v_cap >= threshold) { flip_flop = 0; count_f++; } else if (v_cap <= trigger) { flip_flop = 1; count_r++; } } /* get the v_charge and update each step if it is a node */ if (m_v_charge_node != null) { v_charge = m_v_charge_node[0]; // v_charge = *m_v_charge_node; if ((info.options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) != 0) { v_charge -= 0.5; } } else { v_charge = m_v_charge; } /* Calculate future capacitor voltage. * ref@ http://www.physics.rutgers.edu/ugrad/205/capacitance.html * The formulas from the ref pages have been modified to reflect that we are stepping the change. * dt = time of sample (1/sample frequency) * VC = Voltage across capacitor * VC' = Future voltage across capacitor * Vc = Voltage change * Vr = is the voltage across the resistor. For charging it is Vcc - VC. Discharging it is VC - 0. * R = R1+R2 (for charging) R = R2 for discharging. * Vc = Vr*(1-exp(-dt/(R*C))) * VC' = VC + Vc (for charging) VC' = VC - Vc for discharging. * * We will also need to calculate the amount of time we overshoot the thresholds * dt = amount of time we overshot * Vc = voltage change overshoot * dt = R*C(log(1/(1-(Vc/Vr)))) */ dt = this.sample_time(); /* Sometimes a switching network is used to setup the capacitance. * These may select no capacitor, causing oscillation to stop. */ if (DSD_555_ASTBL__C == 0) { flip_flop = 1; /* The voltage goes high because the cap circuit is open. */ v_cap_next = v_charge; v_cap = v_charge; m_cap_voltage = 0; } else { /* Update charge contstants and exponents if nodes changed */ if (m_has_rc_nodes != 0 && (DSD_555_ASTBL__R1 != m_last_r1 || DSD_555_ASTBL__C != m_last_c || DSD_555_ASTBL__R2 != m_last_r2)) { m_t_rc_bleed = DSD_555_ASTBL_T_RC_BLEED; m_t_rc_charge = DSD_555_ASTBL_T_RC_CHARGE(info); m_t_rc_discharge = DSD_555_ASTBL_T_RC_DISCHARGE; m_exp_bleed = RC_CHARGE_EXP(m_t_rc_bleed); m_exp_charge = RC_CHARGE_EXP(m_t_rc_charge); m_exp_discharge = RC_CHARGE_EXP(m_t_rc_discharge); m_last_r1 = DSD_555_ASTBL__R1; m_last_r2 = DSD_555_ASTBL__R2; m_last_c = DSD_555_ASTBL__C; } /* Keep looping until all toggling in time sample is used up. */ do { if (flip_flop != 0) { if (DSD_555_ASTBL__R1 == 0) { /* Oscillation disabled because there is no longer any charge resistor. */ /* Bleed the cap due to circuit losses. */ if (update_exponent != 0) { exponent = RC_CHARGE_EXP_DT(m_t_rc_bleed, dt); } else { exponent = m_exp_bleed; } v_cap_next = v_cap - (v_cap * exponent); dt = 0; } else { /* Charging */ if (update_exponent != 0) { exponent = RC_CHARGE_EXP_DT(m_t_rc_charge, dt); } else { exponent = m_exp_charge; } v_cap_next = v_cap + ((v_charge - v_cap) * exponent); dt = 0; /* has it charged past upper limit? */ if (v_cap_next >= threshold) { /* calculate the overshoot time */ dt = m_t_rc_charge * Math.Log(1.0 / (1.0 - ((v_cap_next - threshold) / (v_charge - v_cap)))); x_time = dt; v_cap_next = threshold; flip_flop = 0; count_f++; update_exponent = 1; } } } else { /* Discharging */ if (DSD_555_ASTBL__R2 != 0) { if (update_exponent != 0) { exponent = RC_CHARGE_EXP_DT(m_t_rc_discharge, dt); } else { exponent = m_exp_discharge; } v_cap_next = v_cap - (v_cap * exponent); dt = 0; } else { /* no discharge resistor so we immediately discharge */ v_cap_next = trigger; } /* has it discharged past lower limit? */ if (v_cap_next <= trigger) { /* calculate the overshoot time */ if (v_cap_next < trigger) { dt = m_t_rc_discharge * Math.Log(1.0 / (1.0 - ((trigger - v_cap_next) / v_cap))); } x_time = dt; v_cap_next = trigger; flip_flop = 1; count_r++; update_exponent = 1; } } v_cap = v_cap_next; } while (dt != 0); m_cap_voltage = v_cap; } /* Convert last switch time to a ratio */ x_time = x_time / this.sample_time(); switch (m_output_type) { case DISC_555_OUT_SQW: if (count_f + count_r >= 2) { /* force at least 1 toggle */ v_out = m_flip_flop != 0 ? 0 : m_v_out_high; } else { v_out = flip_flop * m_v_out_high; } v_out += m_ac_shift; break; case DISC_555_OUT_CAP: v_out = v_cap; /* Fake it to AC if needed */ if (m_output_is_ac != 0) { v_out -= threshold * 3.0 / 4.0; } break; case DISC_555_OUT_ENERGY: if (x_time == 0) { x_time = 1.0; } v_out = m_v_out_high * (flip_flop != 0 ? x_time : (1.0 - x_time)); v_out += m_ac_shift; break; case DISC_555_OUT_LOGIC_X: v_out = flip_flop + x_time; break; case DISC_555_OUT_COUNT_F_X: v_out = count_f != 0 ? count_f + x_time : count_f; break; case DISC_555_OUT_COUNT_R_X: v_out = count_r != 0 ? count_r + x_time : count_r; break; case DISC_555_OUT_COUNT_F: v_out = count_f; break; case DISC_555_OUT_COUNT_R: v_out = count_r; break; } set_output(0, v_out); m_flip_flop = flip_flop; }