void _lowpass_filter_step(uint32_t n_dims, value_t *input, value_t *output, void *pars) { // Cast the params lowpass_state_t *params = (lowpass_state_t *) pars; register int32_t a = bitsk(params->a); register int32_t b = bitsk(params->b); // Apply the filter to every dimension (realised as a Direct Form I digital // filter). for (uint32_t d = 0; d < n_dims; d++) { // The following is equivalent to: // // output[d] *= params->a; // output[d] += input[d] * params->b; // Compute the next value in a register register int64_t next_output; // Perform the first multiply int32_t current_output = bitsk(output[d]); next_output = __smull(current_output, a); // Perform the multiply accumulate int32_t current_input = bitsk(input[d]); next_output = __smlal(next_output, current_input, b); // Scale the result back down to store it output[d] = kbits(convert_s32_30_s16_15(next_output)); } }
static inline void _print_inputs() { #if LOG_LEVEL >= LOG_DEBUG log_debug("Inputs\n"); bool empty = true; for (index_t i = 0; i < n_neurons; i++) { empty = empty && (bitsk(synapse_types_get_excitatory_input(input_buffers, i) - synapse_types_get_inhibitory_input(input_buffers, i)) == 0); } if (!empty) { log_debug("-------------------------------------\n"); for (index_t i = 0; i < n_neurons; i++) { input_t input = synapse_types_get_excitatory_input(input_buffers, i) - synapse_types_get_inhibitory_input(input_buffers, i); if (bitsk(input) != 0) { log_debug("%3u: %12.6k (= ", i, input); synapse_types_print_input(input_buffers, i); log_debug(")\n"); } } log_debug("-------------------------------------\n"); } #endif // LOG_LEVEL >= LOG_DEBUG }
void _lti_filter_step(uint32_t n_dims, value_t *input, value_t *output, void *s) { // Cast the state lti_state_t *state = (lti_state_t *) s; // Apply the filter to every dimension (realised as a Direct Form I digital // filter). for (uint32_t d = n_dims, dd = n_dims - 1; d > 0; d--, dd--) { // Point to the correct previous x and y values. ab_t *xy = &state->xyz[dd * state->order]; // Create the new output value for this dimension register int64_t output_val = 0; // Direct Form I filter // `m` acts as an index into the ring buffer of historic input and output. for (uint32_t k=0, m = state->n; k < state->order; k++) { // Update the index into the ring buffer, if this would go negative it // wraps to the top of the buffer. if (m == 0) { m += state->order; } m--; // Apply this part of the filter // Equivalent to: // output[dd] += ab.a * xyz.a; // output[dd] += ab.b * xyz.b; ab_t ab = state->abs[k]; ab_t xyz = xy[m]; output_val = __smlal(output_val, bitsk(ab.a), bitsk(xyz.a)); output_val = __smlal(output_val, bitsk(ab.b), bitsk(xyz.b)); } // Include the initial new input xy[state->n].b = input[dd]; // Save the current output for later steps output[dd] = kbits(convert_s32_30_s16_15(output_val)); xy[state->n].a = output[dd]; } // Rotate the ring buffer by moving the starting pointer, if the starting // pointer would go beyond the end of the buffer it is returned to the start. if (++state->n == state->order) { state->n = 0; } }
void filter_update(uint ticks, uint arg1) { use(arg1); if (simulation_ticks != UINT32_MAX && ticks >= simulation_ticks) { spin1_exit(0); } // Update the filters input_filter_step(&g_input, true); // Apply the transform to the input to get the output for (uint j = 0; j < g_filter.size_out; j++) { g_filter.output[j] = 0.0k; for (uint k = 0; k < g_filter.size_in; k++) { g_filter.output[j] += g_filter.transform[j*g_filter.size_in + k] * g_filter.input[k]; } } // Increment the counter and transmit if necessary delay_remaining--; if(delay_remaining == 0) { delay_remaining = g_filter.transmission_delay; uint val = 0x0000; for(uint d = 0; d < g_filter.size_out; d++) { val = bitsk(g_filter.output[d]); spin1_send_mc_packet(g_filter.keys[d], val, WITH_PAYLOAD); spin1_delay_us(g_filter.interpacket_pause); } } }